2012-09-30 22 views
5

que actualmente tienen la siguiente función para leer una matriz o un vector de datos en bruto (_readStream es una std::ifstream):¿Cómo comprobar si los iteradores forman una zona de memoria contigua?

template<typename IteratorType> 
inline bool MyClass::readRawData(
    const IteratorType& first, 
    const IteratorType& last, 
    typename std::iterator_traits<IteratorType>::iterator_category* = nullptr 
    ) 
{ 
    _readStream.read(reinterpret_cast<char*>(&*first), (last-first)*sizeof(*first)); 
    return _readStream.good(); 
} 

Primera pregunta: ¿esta función parece bien para usted?

Como leemos directamente un bloque de memoria, solo funcionará si el bloque de memoria de first a last es contiguo en la memoria. ¿Cómo verificar eso?

+0

Su función hace muchas suposiciones sobre cómo se usará. Sería mejor si fueran explícitos, o al menos documentados. Entre estos supuestos: 1) Que los elementos pueden ser serializados por su representación binaria en la memoria. 2) Que la duración del tiempo de ejecución es la misma que la del que escribió los datos. – Cameron

+3

En realidad, ¿por qué usar iteradores en absoluto cuando la función es completamente no genérica? Su único propósito es copiar elementos a granel en bits en la memoria. Cambie el nombre de la función para reflejar esto, y pídale que tome un puntero y un conteo en lugar de iteradores ... La pregunta en su título aún es interesante :-) – Cameron

+0

Tengo otra función para intercambiar los datos si la endianidad fue diferente, así que el segundo punto no es un problema – Vincent

Respuesta

4

Dejando de lado su función de muestra, nunca puede estar completamente seguro de que los iteradores formarán una memoria contigua sin verificar la dirección de cada elemento entre los dos.

Una prueba de sanidad razonable, sin embargo, sería simplemente comprobar si el área de memoria entre los dos es el mismo que el recuento entre los dos:

assert(&*last - &*first == last - first && 
    "Iterators must represent a contiguous memory region"); 
+1

Estoy bastante seguro de que '& * last - & * first' es un comportamiento indefinido a menos que' * first' and '* last' son parte de la misma matriz, y eso es lo que estamos tratando de determinar. –

+0

@BenjaminLindley No creo que sea indefinido, es una mera sustracción del puntero. Podríamos obtener algunos resultados extraños, como valores negativos, si el contenedor no es contiguo, pero eso se compararía con la distancia entre los dos iteradores. Creo que es bastante seguro suponer que el póster al menos requerirá que su algoritmo requiera iteradores de acceso aleatorio desde el mismo contenedor, independientemente de si el contenedor es contiguo o no. Sin embargo, es una cosa extraña que el poster está tratando de hacer. – stinky472

+7

@ stinky472: Sí, entiendo que es una resta del puntero. Lo que estoy diciendo es que a menos que los punteros apunten a objetos en la misma matriz, la operación de resta no está definida, según el estándar, 5.7.6 –

2
typename std::iterator_traits<IteratorType>::iterator_category* = nullptr 

esto es inútil porque std::iterator_traits tiene una plantilla primaria con un tipo de miembro unconditonally definido iterator_category. Se asume tácitamente que el parámetro de plantilla es un iterador y que, si no es una violación de condición previa, no obtendrá SFINAE, pero sí un error grave si se intenta lo anterior con una instanciación no válida.

Como leemos directamente un bloque de memoria, solo funcionará si el bloque de memoria del primero al último está contiguo en la memoria. ¿Cómo verificar eso?

No sé qué requisitos exactos pondría en un concepto de 'contiguo en la memoria'. Sin embargo, ¿has considerado lo siguiente?

template<typename T> 
bool readRawData(T* first, T* last); 

con la condición previa de que [ first, last) ser un válido gama puntero-as-iterador en una matriz.

Si desea agregar más requisitos al T (por ejemplo, copia de seguridad trivial ya que utiliza read), puede expresarlos/documentarlos también.

3

n4183 es un papel que va sobre la idea de agregando un rasgo de iterador contiguo. Actualmente está en consideración para C++ 1z (con suerte C++ 17).

Debajo, puede hacer std::is_contiguous_iterator<It>::value y obtener si It es un iterador contiguo o no. (Esto requerirá soporte del diseñador del iterador).

+0

¿Esto fue aceptado? – einpoklum

Cuestiones relacionadas