2012-09-30 9 views
5

Obecnie mam następującą funkcję odczytywania tablicy lub wektor surowych danych (_readStream jest std::ifstream):Jak sprawdzić, czy iteratory tworzą ciągłą strefę pamięci?

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

Pierwsze pytanie: czy ta funkcja wydaje się ok dla ciebie?

Ponieważ odczytujemy bezpośrednio blok pamięci, działa on tylko wtedy, gdy blok pamięci od first do last jest ciągły w pamięci. Jak to sprawdzić?

+0

Twoja funkcja zawiera wiele założeń dotyczących sposobu jej użycia. Byłoby lepiej, gdyby były wyraźne, a przynajmniej udokumentowane. Wśród tych założeń: 1) Elementy mogą być serializowane przez ich binarną reprezentację w pamięci. 2) że endianess środowiska wykonawczego jest taki sam jak ten, który zapisał dane. – Cameron

+3

Właściwie dlaczego warto używać iteratorów, gdy funkcja jest całkowicie nietypowa? Jego jedynym celem jest częściowe kopiowanie elementów bitowych do pamięci. Zmień nazwę funkcji, aby to odzwierciedlić, i poproś o wskaźnik i liczbę zamiast iteratorów ... Pytanie w tytule jest nadal interesujące :-) – Cameron

+0

Mam inną funkcję do zamiany danych, jeśli endianness był inny, więc twój Drugi punkt nie stanowi problemu. – Vincent

Odpowiedz

4

Pomijając funkcję próbki, nigdy nie możesz być całkowicie pewny, że iteratory utworzą ciągłą pamięć bez sprawdzania adresu każdego elementu między tymi dwoma.

Rozsądny Test rozsądku, choć byłoby po prostu sprawdzić, czy obszar pamięci między nimi jest taka sama, jak liczyć między nimi:

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

Jestem całkiem pewien, że '& * last - & * first' jest niezdefiniowanym zachowaniem, chyba że' * first' i '* last' są częścią tej samej tablicy i właśnie to próbujemy ustalić. –

+0

@BenjaminLindley Nie sądzę, by to było nieokreślone - to tylko odejmowanie wskaźnika. Możemy otrzymać dziwne wyniki, takie jak wartości ujemne, jeśli kontener nie jest ciągły, ale będzie to sprawdzane na podstawie odległości między dwoma iteratorami. Sądzę, że dość bezpiecznie założyć, że plakat będzie wymagał co najmniej, aby jego algorytm wymagał iteratorów z dostępem losowym z tego samego kontenera, niezależnie od tego, czy ten kontener jest przylegający. Mimo to jest to dziwna rzecz, którą próbuje zrobić plakat. – stinky472

+7

@ stinky472: Tak, rozumiem, że to odejmowanie wskaźnika. Mówię tylko, że jeśli wskaźniki nie wskazują obiektów w tej samej tablicy, operacja odejmowania jest niezdefiniowana, zgodnie ze standardem, 5.7.6 –

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

To jest bezużyteczne, ponieważ std::iterator_traits ma podstawowy szablon z krytym unconditonally określonego rodzaju członkiem iterator_category. Milcząco przyjmuje się, że parametr szablonu jest iteratorem i że jest to naruszenie warunków wstępnych, jeśli tak nie jest - jako taki nie otrzymasz SFINAE, ale poważny błąd, jeśli powyższe zostanie podjęte z nieprawidłową instancją.

Jak czytamy bezpośrednio blok pamięci, to będzie działać tylko wtedy, gdy blok pamięci od pierwszego do ostatniego przylega w pamięci. Jak to sprawdzić?

Nie wiem, jakie dokładnie wymagania można umieścić w koncepcji "ciągłej w pamięci". Czy jednak rozważyłeś następujące rzeczy?

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

z warunkiem, że [ first, last) być ważnym wskaźnikiem-as-iteracyjnej zakres w tablicy.

Jeśli chcesz wprowadzić dodatkowe wymagania dotyczące T (np. Banalna możliwość kopiowania, ponieważ korzystasz z read), możesz je również wyrazić/udokumentować.

3

n4183 jest papier, który przechodzi nad ideą dodanie ciągłej cechy iteracyjnej. Jest on obecnie rozważany pod kątem C++ 1z (miejmy nadzieję, C++ 17).

Pod nim można wykonać std::is_contiguous_iterator<It>::value i uzyskać, jeśli It jest iteratorem ciągłym lub nie. (Będzie to wymagało wsparcia od projektanta iteratora).

+0

Czy zostało to zaakceptowane? – einpoklum

Powiązane problemy