2009-01-13 21 views
44

Jaki jest najlepszy sposób przechowywania danych binarnych w C++? Opcje, o ile mogę powiedzieć, w dużym stopniu sprowadzają się do używania ciągów lub wektorów < char s. >. (Pomijam możliwość char * s i malloc(), ponieważ mam na myśli konkretnie C++)."Właściwy" sposób przechowywania danych binarnych za pomocą C++/STL

Zazwyczaj używam łańcucha znaków, ale nie jestem pewien, czy brakuje mi narzutów, czy też konwersji, które wewnętrznie STL może zepsuć z poprawnością danych binarnych. Czy ktoś ma jakieś wskazówki (har) na ten temat? Sugestie lub preferencje w taki czy inny sposób?

Odpowiedz

38

wektor znaku jest ładny, ponieważ pamięć jest ciągła. Dlatego możesz go używać z wieloma API C, takimi jak gniazda berkley lub API plików. Możesz wykonać następujące czynności, na przykład:

std::vector<char> vect; 
    ... 
    send(sock, &vect[0], vect.size()); 

i będzie działać poprawnie.

Można zasadniczo traktować go tak, jak każdy inny dynamicznie przydzielany bufor znaków. Możesz skanować w górę iw dół, szukając magicznych liczb lub wzorów. Możesz je częściowo przeanalizować. W celu odbierania z gniazda można bardzo łatwo zmienić jego rozmiar, aby dołączyć więcej danych.

Wadą jest zmiana rozmiaru nie jest strasznie wydajna (zmiana rozmiaru lub prealocate roztropnie) i usunięcie z przodu tablicy będzie również bardzo nieefektywne. Jeśli potrzebujesz, powiedzmy, popuwać tylko jeden lub dwa znaki w czasie z przodu struktury danych bardzo często, kopiowanie do deque przed tym przetwarzaniem może być opcją. Kosztuje to kopię, a pamięć deque nie jest ciągła, więc nie można po prostu przekazać wskaźnika do C API.

Podsumowując, poznaj struktury danych i ich kompromisy przed rozpoczęciem nurkowania, jednak wektor znaków jest zazwyczaj tym, co widzę w ogólnej praktyce.

+2

dobra odpowiedź. dla części uczącej się: znalazłem ładne zdjęcie pokazujące wykorzystanie kontenerów jakiś czas temu i umieściłem go w tej odpowiedzi: http://stackoverflow.com/questions/366432/extending-stdlist#366710 –

6

Do tego również używam std::string i nigdy nie miałem z tym problemu.

Jeden "wskaźnik", do którego przed chwilą otrzymałem ostry komunikat z fragmentu kodu: wczytując ciąg z bloku danych binarnych, użyj formularza konstruktora std::string(startIter, endIter), a nie formularza std::string(ptr, offset, length) - ten ostatni tworzy założenie, że wskaźnik wskazuje na łańcuch w stylu C i ignoruje cokolwiek po pierwszym znaku zerowym (kopiuje "do" określonych znaków).

+0

Hmmm. Według http://www.cplusplus.com/reference/string/string/string.html, std :: string (char * ptr, offset, length) ctor powinien skopiować * wszystkie * długości bajtów, nawet włączając zero bajtów. Jest to std :: string (string const &, offset, length) ctor, który kopiuje * do * długości bajtów. –

+0

To zachęciło mnie do ponownego sprawdzenia i wygląda na to, że konstruktor * is * no std :: string (char * ptr, offset, length). Konstruktor, że trwa offset i długość wymaga std :: string jako pierwszy parametr, więc było automatycznego budowania ciąg z bajtów, co jest, co go obcięty. –

+0

Masz rację. Przepraszam, miałem na myśli std :: string (char * ptr, size_t length) ctor powinien skopiować wszystkie bajty. –

3

Powinieneś używać kontenera char, ale pojemnik, którego chcesz użyć, zależy od twojej aplikacji.

Chary mają kilka właściwości, które sprawiają, że są one przydatne do przechowywania danych binarnych: standard nie dopuszcza żadnego "dopełnienia" dla typu danych char, co jest ważne, ponieważ oznacza to, że nie będzie można uzyskać śmieci w układzie binarnym. Każdy znak ma również dokładnie jeden bajt, co czyni go jedynym zwykłym typem danych (POD) o ustawionej szerokości (wszystkie inne są określone w kategoriach górnych i/lub dolnych granic).

Dyskusja na temat odpowiedniego kontenera STI, w którym przechowywane są znaki, jest obsługiwana również przez Douga powyżej. To, czego potrzebujesz, zależy całkowicie od twojego przypadku użycia. Jeśli przechowujesz tylko blok danych, przez które przechodzisz, bez specjalnego szukania, dołączania/usuwania lub łączenia potrzeb, wolałbym wektor, który uczyniłby twoje intencje bardziej przejrzystymi niż std :: string, który wiele bibliotek i funkcji przyjmie zawiera ciąg znaków w stylu c zakończony znakiem N.

8

Największy problem z std :: string polega na tym, że obecny standard nie gwarantuje, że jego pamięć bazowa jest ciągła.Jednak nie ma znanych implementacji STL, w których ciąg nie jest ciągły, więc w praktyce prawdopodobnie nie zawiedzie. W rzeczywistości, nowy standard C++ 0x zamierza rozwiązać ten problem, poprzez upoważnienie że std :: string wykorzystuje ciągłą bufor, takie jak std :: vector.

Kolejnym argumentem przeciw jest to, że ciąg jego nazwa sugeruje, że zawiera ciąg znaków, a nie binarny bufora, co może powodować zamieszanie z tymi, którzy odczytać kodu.

To powiedziawszy, polecam wektor również.

Powiązane problemy