2012-09-30 9 views
5

ich zur Zeit die folgende Funktion hat einen Array oder einen Vektor von Rohdaten zu lesen (_readStream ist eine std::ifstream):Wie überprüft man, ob Iteratoren eine zusammenhängende Speicherzone bilden?

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(); 
} 

Erste Frage: Ist diese Funktion scheint für Sie in Ordnung?

Da wir direkt einen Speicherblock lesen, wird es nur funktionieren, wenn der Speicherblock von first bis last zusammenhängend im Speicher ist. Wie überprüft man das? Diese

+0

Ihre Funktion macht viele Annahmen darüber, wie sie verwendet werden. Es wäre besser, wenn sie explizit oder zumindest dokumentiert wären. Unter diesen Annahmen: 1) Dass Elemente durch ihre binäre Darstellung im Speicher serialisiert werden können. 2) Dass die Endgültigkeit der Laufzeit dieselbe ist wie diejenige der Daten, die die Daten geschrieben haben. – Cameron

+3

Warum überhaupt Iteratoren verwenden, wenn die Funktion vollständig nicht-generisch ist? Der einzige Zweck besteht darin, Elemente in den Speicher zu kopieren. Benennen Sie die Funktion um, um dies widerzuspiegeln, und nehmen Sie einen Zeiger und eine Zählung anstelle von Iteratoren ... Die Frage in Ihrem Titel ist immer noch interessant :-) – Cameron

+0

Ich habe eine andere Funktion, um die Daten zu tauschen, wenn die Endianess anders war als Ihre zweiter Punkt ist kein Problem. – Vincent

Antwort

4

Abgesehen von Ihrer Beispielfunktion können Sie nie ganz sicher sein, dass Iteratoren einen zusammenhängenden Speicher bilden, ohne die Adresse jedes Elements zwischen den beiden zu überprüfen.

Eine vernünftige geistige Gesundheit Test, wäre aber nur zu prüfen, ob der Speicherbereich zwischen den beiden die gleiche wie die Zählung zwischen den beiden ist:

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

Ich bin ziemlich sicher, dass '& * last - & * first' ein undefiniertes Verhalten ist, es sei denn' * first' und '* last 'sind Teil des gleichen Arrays, und genau das versuchen wir zu bestimmen. –

+0

@BenjaminLindley Ich glaube nicht, dass es undefiniert wäre - es ist eine bloße Zeigersubtraktion. Wenn der Container nicht zusammenhängend ist, könnten wir einige seltsame Ergebnisse wie negative Werte erhalten, die jedoch mit dem Abstand zwischen den beiden Iteratoren verglichen werden. Ich denke, es ist ziemlich sicher davon auszugehen, dass das Poster zumindest seinen Algorithmus benötigt, um Random-Access-Iteratoren aus demselben Container zu verlangen, unabhängig davon, ob dieser Container zusammenhängend ist oder nicht. Trotzdem ist es eine seltsame Sache, die das Poster versucht zu tun. – stinky472

+7

@ stinky472: Ja, ich verstehe, dass es Zeiger Subtraktion ist. Was ich sage ist, dass, wenn die Zeiger nicht auf Objekte im selben Array zeigen, die Subtraktionsoperation nicht definiert ist, wie im Standard, 5.7.6 –

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

ist nutzlos, da std::iterator_traits eine Primärschablone mit einem unconditonally definierten Elementtyp iterator_category. Es wird stillschweigend angenommen, dass der Template-Parameter ein Iterator ist und dass es eine Vorbedingungverletzung ist, wenn dies nicht der Fall ist - als solche erhält man keinen SFINAE, sondern einen schweren Fehler, wenn das obige mit einer ungültigen Instanziierung versucht wird.

Da wir direkt einen Speicherblock lesen, funktioniert es nur, wenn der Speicherblock vom ersten bis zum letzten Speicher zusammenhängend ist. Wie überprüft man das?

Ich weiß nicht, welche genauen Anforderungen Sie an ein "zusammenhängendes in Speicher" -Konzept stellen würden. Haben Sie jedoch Folgendes in Betracht gezogen?

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

mit der Voraussetzung, dass ein gültiger Zeiger-as-Iterator-Bereich in einem Array sein [ first, last).

Wenn Sie weitere Anforderungen an T setzen möchten (z. B. triviale Kopierbarkeit, da Sie read verwenden), können Sie diese auch ausdrücken/dokumentieren.

3

n4183 ist ein Papier, das über die Idee geht Hinzufügen eines fortlaufenden Iteratormerkmals. Es wird derzeit für C++ 1z (hoffentlich C++ 17) in Betracht gezogen.

Darunter können Sie std::is_contiguous_iterator<It>::value tun und erhalten, wenn It ein zusammenhängender Iterator ist oder nicht. (Dies erfordert Unterstützung vom Entwickler des Iterators).

+0

Wurde das akzeptiert? – einpoklum

Verwandte Themen