2009-10-12 3 views
22

Welcher ist ein besserer C++ - Container für das Halten und Zugreifen auf Binärdaten?Vektor <unsigned char> vs Zeichenfolge für binäre Daten

std::vector<unsigned char> 

oder

std::string 

Ist ein effizienter als die anderen?
Ist eine mehr "richtige" Verwendung?

+0

Werfen Sie einen Blick auf diesen Beitrag über die Verwendung von Char vs unsigned Char für Binärdaten: http://StackOverflow.com/Questions/277655/Why-Do-C-Strom-use-char-instead-of-unsigned-char –

Antwort

26

Sie sollten std::vector über std::string bevorzugen. In den meisten Fällen können beide Lösungen fast gleichwertig sein, aber std::string s sind speziell für die Verarbeitung von Strings und Strings entwickelt und das ist nicht Ihre beabsichtigte Verwendung.

+0

"Sagen Sie, dass die Standard-Charaktereigenschaften bestimmen, dass" a "und" á "äquivalent sind. Das ist eine schlechte Annahme. Siehe die Antwort, die ich als Fortsetzung zu diesem Kommentar geschrieben habe. –

+0

Ich überprüft, und Sie haben Recht, dass der Standard definiert die Spezialisierung 'char_traits ' und mit der Standard-Spezialisierung, Zuordnung, Vergleiche und Bestellung sind als Entsprechung für die integrierte char-Typ definiert. –

+0

Also mit Standard Char_traits würde std :: string nicht anders als die entsprechenden std :: vector? – kalaxy

-1

Wenn Sie nur Ihre Binärdaten speichern möchten, können Sie bitset verwenden, die für die Speicherplatzzuweisung optimiert. Andernfalls gehen Sie für vector, wie es für Ihre Verwendung angemessener ist.

+2

Bitset ist keine gute Wahl. Wie werden Sie die Daten ohne Casting wieder abrufen? Wie liest man leicht ein Byte aus einem Bitset? Dies ist nicht die richtige Anwendung für Bitset. –

+0

Daher "wenn Sie nur Ihre Binärdaten speichern möchten". Dies ist in einigen speicherintensiven Prozessen wichtig - z. Wenn Sie mit Binärbildern arbeiten, möchten Sie sie vorübergehend speichern und später wiederverwenden. – Jacob

+0

Wie oft speichern Sie eigentlich nur Daten? Wenn ich es speichern wollte, würde ich eine Datei oder nur ein Array oder einen Vektor verwenden. Welche Vorteile hat Bitset für den Speicher? Wie erhalten Sie Ihre Binärdaten überhaupt in ein Bitset? Bitset hat wirklich miese Konstruktoren für diesen Zweck. Hast du das tatsächlich versucht? Bitset hat einen Standardkonstruktor, einen Konstruktor, der eine vorzeichenlose Länge annimmt, und eine, die eine Zeichenfolge benötigt. Nicht wirklich praktisch für diesen Zweck. –

13

Beide sind korrekt und ebenso effizient. Die Verwendung eines solchen anstelle eines einfachen Arrays dient nur dazu, die Speicherverwaltung zu erleichtern und sie als Argument zu übergeben.

Ich benutze Vektor, weil die Absicht ist klarer als mit String.

Bearbeiten: C++ 03 Standard garantiert nicht std::basic_string Speicherkontiguität. Aus praktischer Sicht gibt es jedoch keine kommerziellen nicht zusammenhängenden Implementierungen. C++ 0x ist auf standardize that fact festgelegt.

+0

Es gibt keine Möglichkeit, dass std :: string für nicht qualifizierte "Binärdaten" "korrekt" ist. –

+1

von Sgi: "Die basic_string-Klasse stellt eine Zeichenfolge dar. Sie enthält alle üblichen Operationen einer Sequenz und zusätzlich Standard-String-Operationen wie Suchen und Verketten." Warum ist das falsch? Ich stimme zu, es ist nicht der beste Ansatz (wie ich in meiner Antwort sage), aber es ist nicht falsch. –

+0

So funktioniert string genauso gut wie der Vektor, weil er gewissermaßen die Funktionalität eines Vektors erweitert, aber die einzige Funktionalität, die ich brauche ([] oder ähnliches), ist in beiden enthalten? (Ja, ich weiß, dass String nicht vom Vektor erbt.) – kalaxy

4

Ist einer effizienter als der andere?

Dies ist die falsche Frage.

Ist eine mehr "richtige" Verwendung?

Dies ist die richtige Frage.
Es kommt darauf an. Wie werden die Daten verwendet? Wenn Sie die Daten in einer Zeichenfolge wie fashon verwenden möchten, sollten Sie sich für std :: string entscheiden, da die Verwendung von std :: vector nachfolgende Maintainer verwirren kann. Wenn andererseits der Großteil der Datenmanipulation wie einfache Mathematik oder Vektor aussieht, ist ein std :: vector besser geeignet.

-1

Vergleichen Sie diese 2 und wählen Sie selbst, was für Sie spezifischer ist. Beide sind sehr robust, arbeiten mit STL-Algorithmen ... Wählen Sie selbst, welche für Ihre Aufgabe effektiver ist

-2

Persönlich bevorzuge ich std :: string, da string :: data() für mich viel intuitiver ist, wenn ich meinen binären Puffer wieder in C-kompatibler Form haben möchte. Ich weiß, dass Vektorelemente garantiert zusammenhängend gespeichert werden. Das Trainieren im Code fühlt sich ein wenig beunruhigend an.

Dies ist eine Stilentscheidung, die ein einzelner Entwickler oder ein Team selbst treffen sollte.

+0

Sie bevorzugen eine Zeichenfolge für Nicht-String-Daten? Anstatt den Container zu verwenden * entworfen * für die zusammenhängende Speicherung von Daten jeglicher Art? – jalf

+2

Lasst uns nicht vergessen, dass das der Stil ist. Perfekt funktionierender und standardkonformer Code für binäre Puffer kann mit jeder dieser Klassen erstellt werden. Ich würde argumentieren, dass der Vektor auch nicht als binärer Puffer ausgelegt ist. Es ist kompatibel, aber Sie müssen zu Algorithmen oder C-Tricks zurückkehren, um die Arbeit zu erledigen. Nicht alle String-Operationen sind sicher, aber einige von ihnen sind sehr nützlich, um den Code sauberer und wartungsfreundlicher zu machen. –

+0

Vektor ist ziemlich geeignet, binäre Daten zu speichern, z.B. Vektor v (256). Ich betrachte & v [0] keinen "C-Trick". –

1

Dies ist ein Kommentar zu Dribeas Antwort. Ich schreibe es als eine Antwort, um den Code zu formatieren.

Dies ist die char_traits Funktion vergleichen, und das Verhalten ist sehr gesund:

static bool 
lt(const char_type& __c1, const char_type& __c2) 
{ return __c1 < __c2; } 

template<typename _CharT> 
int 
char_traits<_CharT>:: 
compare(const char_type* __s1, const char_type* __s2, std::size_t __n) 
{ 
    for (std::size_t __i = 0; __i < __n; ++__i) 
if (lt(__s1[__i], __s2[__i])) 
    return -1; 
else if (lt(__s2[__i], __s1[__i])) 
    return 1; 
    return 0; 
} 
+0

Ist dieses Verhalten im Standard gut definiert? – gnud

+0

+1: @gnud: Nicht im Allgemeinen, aber fnieto ist richtig (ich habe es gerade überprüft), dass der Standard die Spezialisierung von Merkmalen für char definiert, wobei 'assign',' eq' und 'lt' als eingebaut definiert werden müssen Operatoren =, == und

0

Soweit Lesbarkeit betrifft, ziehe ich std :: vector. std :: vector sollte in diesem Fall der Standard-Container sein: Die Absicht ist klarer und wie bereits von anderen Antworten gesagt wurde, ist es bei den meisten Implementierungen auch effizienter.

Bei einer Gelegenheit bevorzuge ich jedoch std :: string über std :: vector. Schauen wir uns die Unterschrift ihrer Bewegung Konstrukteuren in C++ 11 aussehen:

vector (vector&& x);

string (string&& str) noexcept;

Bei dieser Gelegenheit habe ich wirklich einen noexcept bewegen Konstruktor benötigt. std :: string liefert es und std :: vector nicht.

1

Für die längste Zeit stimmte ich mit den meisten Antworten hier überein. Aber gerade heute traf mich, warum es sinnvoller sein könnte, std::string über zu verwenden.

Wie die meisten zustimmen, wird die Verwendung eines einzigen gut funktionieren. Oftmals können Dateidaten jedoch auch im Textformat vorliegen (häufiger, wenn XML nun Mainstream geworden ist). Dies macht es einfach, im Debugger angezeigt zu werden, wenn es relevant wird (und diese Debugger werden es Ihnen oft ermöglichen, die Bytes der Zeichenfolge zu navigieren). Aber viel wichtiger ist, dass viele existierende Funktionen, die für eine Zeichenkette verwendet werden können, leicht für Datei-/Binärdaten verwendet werden können. Ich habe festgestellt, dass ich mehrere Funktionen geschrieben habe, um sowohl Strings als auch Byte-Arrays zu handhaben, und erkannte, wie sinnlos alles war.