2012-09-30 13 views
5

ho attualmente la seguente funzione per leggere un array o un vettore di dati grezzi (_readStream è una std::ifstream):Come verificare se gli iteratori formano una zona di 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(); 
} 

Prima domanda: non questa funzione sembra ok per voi?

Come si legge direttamente un blocco di memoria, funzionerà solo se il blocco di memoria da first a last è contiguo nella memoria. Come controllarlo?

+0

La funzione fornisce molte ipotesi su come verrà utilizzata. Sarebbe meglio se fossero espliciti, o almeno documentati. Tra questi presupposti: 1) che gli elementi possono essere serializzati dalla loro rappresentazione binaria in memoria. 2) Che l'endianess del runtime è uguale a quello di quello che ha scritto i dati. – Cameron

+3

In realtà, perché utilizzare gli iteratori quando la funzione è completamente non generica? Il suo unico scopo è quello di copiare gli elementi in bit a bit in memoria. Rinomina la funzione per riflettere questo e prendi un puntatore e un conteggio invece di iteratori ... La domanda nel tuo titolo è comunque interessante :-) – Cameron

+0

Ho un'altra funzione per scambiare i dati se l'endianness era diverso, quindi il tuo il secondo punto non è un problema. – Vincent

risposta

4

Lasciando da parte la funzione di esempio, non si può mai essere completamente sicuri che gli iteratori formeranno una memoria contigua senza controllare l'indirizzo di ogni elemento tra i due.

Un test di integrità ragionevole, però, sarebbe solo controllare se l'area di memoria tra i due è lo stesso del valore tra i due:

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

Sono abbastanza sicuro che '& * last - & * first' è un comportamento indefinito a meno che non sia' * first' e '* l'ultimo è parte dello stesso array, ed è proprio quello che stiamo cercando di determinare. –

+0

@BenjaminLindley Non penso che sarebbe indefinito - è una mera sottrazione puntatore. Potremmo ottenere risultati strani come valori negativi se il contenitore non è contiguo, ma verrebbe controllato rispetto alla distanza tra i due iteratori. Penso che sia abbastanza sicuro presumere che il poster richieda almeno che il suo algoritmo richieda iteratori ad accesso casuale dallo stesso contenitore, indipendentemente dal fatto che il contenitore sia contiguo o meno. Tuttavia, è una cosa strana che il poster sta cercando di fare. – stinky472

+7

@ stinky472: Sì, capisco che si tratta della sottrazione del puntatore. Quello che sto dicendo è che, a meno che i puntatori non puntino a oggetti nella stessa matrice, l'operazione di sottrazione non è definita, come per lo standard, 5.7.6 –

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

Questo è inutile perché std::iterator_traits ha un modello primario con un tipo di elemento unconditonally definito iterator_category. Si presume tacitamente che il parametro template sia un iteratore e che si tratti di una violazione di precondizione se non lo è, in quanto non si otterrà SFINAE ma un errore grave se si tenta di eseguire una istanziazione non valida.

Come si legge direttamente un blocco di memoria, funzionerà solo se il blocco di memoria dal primo all'ultimo è contiguo in memoria. Come controllarlo?

Non so quali siano i requisiti esatti da inserire in un concetto di "contiguità in memoria". Hai comunque considerato quanto segue?

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

con il presupposto che [ first, last) essere un puntatore-as-iteratore intervallo valido in una matrice.

Se si desidera aggiungere ulteriori requisiti allo T (ad esempio, la copiabilità banale dal momento che si utilizza read) è possibile esprimere/documentare anche quelli.

3

n4183 è una carta che va oltre l'idea di aggiungendo un tratto iteratore contiguo. Attualmente è in fase di studio per C++ 1z (si spera C++ 17).

Sotto di esso, è possibile fare std::is_contiguous_iterator<It>::value e ottenere se It è un iteratore contiguo o meno. (Ciò richiederà il supporto del progettista dell'iteratore).

+0

Era accettato? – einpoklum

Problemi correlati