Sollten Arrays in C ++ verwendet werden?

95

Da std::listund std::vectorexist, gibt es einen Grund traditionellen C - Arrays in C ++ zu verwenden, oder sollten sie vermieden werden, wie malloc?

Andreas
quelle
18
@Als: Diese Frage betrifft den Unterschied zwischen zwei bestimmten Containern, während diese Frage den Unterschied zwischen Raw-Arrays und Standardcontainern im Allgemeinen betrifft.
Jon Purdy

Antworten:

109

In C ++ 11, wo std::arrayverfügbar, lautet die Antwort "Ja, Arrays sollten vermieden werden". Vor C ++ 11 müssen Sie möglicherweise C-Arrays verwenden, um Arrays im automatischen Speicher (dh auf dem Stapel) zuzuweisen.

dasblinkenlight
quelle
3
Vielen Compilern fehlt jedoch immer noch die Unterstützung von C ++ 11. Sie müssen sich entscheiden, wann es besser ist, das eine als das andere zu verwenden, da std :: array
fehlt
4
std :: array ist eine Vorlage, die sich auf große Projekte hinsichtlich der Erstellungszeit und möglicherweise der Codegröße auswirkt, da die Vorlage für jede Kombination von T, N neu instanziiert wird.
Zvrba
std :: vector garantiert standardmäßig die Datenausrichtung, sodass sie fast überall verwendet werden kann. Mit C ++ 11 gibt es wirklich keinen Grund, C-Arrays zu verwenden.
Nils
16
@ Null-Arrays garantieren auch die Ausrichtung. Außerdem ist die automatische Speicherzuweisung ("der Stapel") viel schneller als die dynamische Speicherzuweisung. Wenn ich weiß, dass ich genau 3 Elemente habe [z. B. Koordinaten eines Dreiecks], gibt es keinen Grund, einen Vektor zu verwenden.
Zvrba
9
@zvrba - Überprüfen Sie die generierte Assembly, wenn Sie std :: array vs C-Arrays verwenden. Kein Unterschied.
Nemanja Trifunovic
85

Auf jeden Fall, obwohl mit std::arrayin C ++ 11, praktisch nur für statische Daten. Arrays im C-Stil haben drei wichtige Vorteile gegenüber std::vector:

  • Sie erfordern keine dynamische Zuordnung. Aus diesem Grund sind Arrays im C-Stil vorzuziehen, wenn Sie wahrscheinlich viele sehr kleine Arrays haben. Sagen Sie so etwas wie einen n-dimensionalen Punkt:

    template <typename T, int dims>
    class Point
    {
        T myData[dims];
    // ...
    };
    

    Normalerweise könnte man sich einen dimssehr kleinen (2 oder 3), Teinen eingebauten Typ ( double) vorstellen , bei dem Sie möglicherweise std::vector<Point>Millionen von Elementen haben. Sie wollen definitiv nicht Millionen von dynamischen Zuordnungen von 3 Doppel.

  • Die statische Initialisierung unterstützen. Dies ist nur ein Problem für statische Daten, bei denen Folgendes der Fall ist:

    struct Data { int i; char const* s; };
    Data const ourData[] =
    {
        { 1, "one" },
        { 2, "two" },
        //  ...
    };
    

    Dies ist häufig der Verwendung eines Vektors (und std::string) vorzuziehen , da alle Initialisierungsprobleme in der Reihenfolge vermieden werden. Die Daten werden vorinstalliert, bevor ein tatsächlicher Code ausgeführt werden kann.

  • In Bezug auf das Obige kann der Compiler schließlich die tatsächliche Größe des Arrays aus den Initialisierern berechnen. Sie müssen sie nicht zählen.

Wenn Sie Zugriff auf C ++ 11 haben, werden std::arraydie ersten beiden Probleme gelöst und sollten im ersten Fall definitiv gegenüber Arrays im C-Stil verwendet werden. Der dritte Punkt wird jedoch nicht angesprochen, und wenn das Compiler das Array entsprechend der Anzahl der Initialisierer dimensioniert, ist dies immer noch ein triftiger Grund, Arrays im C-Stil zu bevorzugen.

James Kanze
quelle
11
Durch die Array-Initialisierung im C-Stil müssen Sie sich nicht mehr wiederholen. int i[] = { 1, 2, 3 };arbeitet weiter mit int i[] = { 1, 2, 3, 4 };. array<int, 3>muss manuell geändert werden auf array<int, 4>.
10
@JoeWreschnig Eine Änderung, die Sie leicht vergessen können. Wenn Sie ein Element hinzufügen, sollte sich der Compiler beschweren. Wenn Sie jedoch eines entfernen, erhalten Sie am Ende ein zusätzliches, 0-initialisiertes Element. Ich verwende immer noch häufig Arrays im C-Stil für diese Art von statischen Daten.
James Kanze
3
Der erste Satz macht keinen Sinn.
Konrad Rudolph
4
Der dritte Punkt kann ziemlich elegant gelöst werden, indem eine ähnliche make_arrayFunktion wie make_pairusw. verwendet wird. Hutspitze zu @R. Martinho Fernandes .
Konrad Rudolph
@KonradRudolph: Sicher tut es. Andreas fragt "Sollten Arrays in C ++ verwendet werden?", Worauf James antwortet "Auf jeden Fall, obwohl std::arrayin C ++ 11 [sie sollten] praktisch nur für statische Daten verwendet werden".
Jon Purdy
15

Sagen Sie niemals "nie", aber ich würde zustimmen, dass ihre Rolle durch echte Datenstrukturen von STL stark eingeschränkt wird.

Ich würde auch sagen, dass die Kapselung in Objekten die Auswirkungen solcher Entscheidungen minimieren sollte. Wenn das Array ein privates Datenelement ist, können Sie es ein- oder austauschen, ohne die Clients Ihrer Klasse zu beeinträchtigen.

Duffymo
quelle
11

Ich habe an sicherheitskritischen Systemen gearbeitet, bei denen Sie die dynamische Speicherzuordnung nicht verwenden können. Der Speicher muss immer auf dem Stapel sein. Daher würden Sie in diesem Fall Arrays verwenden, da die Größe zur Kompilierungszeit festgelegt ist.

Ed Heal
quelle
8
Vor C ++ 11 hätte ich zugestimmt, aber std::array<T>auf die Stapel verteilt und hat im Grunde keinen Overhead auf einem Raw-Array.
111111
5
@ 111111 - Einverstanden. Aber ich weiß, dass einige Leute in dieser Branche noch nicht zu C ++ 11 gewechselt sind
Ed Heal
Ich weiß, deshalb habe ich dich nicht abgelehnt, aber ich denke, Boost hatte eine Version und es ist einfach, deine eigene zu rollen.
111111
6
In sicherheitskritischen Systemen verwenden Sie jedoch keine neuen (weniger getesteten) Compilerfunktionen und keinen Boost.
James Kanze
3
Viele sicherheitskritische Systeme basieren auf ALTEN Compilern, die nicht einmal über die neueren Compilerfunktionen verfügen, da das Ändern von Toolchains ein langsamer und teurer Prozess ist, der eine Menge Papierkram, Tests und Zertifizierungen erfordert.
Brian McFarland
6

arrayin c++bietet Ihnen eine schnelle Alternative mit fester Größe von dynamischer Größe std::vectorund std::list. std :: array ist eine der Ergänzungen in c++11. Es bietet den Vorteil von Standardcontainern und bietet dennoch die Aggregattypsemantik von Arrays im C-Stil.

Also c++11würde ich in std::array, wo es erforderlich ist, sicherlich über Vektor verwenden. Aber ich würde ein Array im C-Stil vermeiden C++03.

Vikas
quelle
4

Meistens, nein , ich kann mir keinen Grund vorstellen, Raw-Arrays beispielsweise zu verwenden vectors. Wenn der Code neu ist .

Möglicherweise müssen Sie auf die Verwendung von Arrays zurückgreifen, wenn Ihre Bibliotheken mit Code kompatibel sein müssen, der Arrays und Rohzeiger erwartet.

Luchian Grigore
quelle
1
... aber seit C ++ 03 "hat" ein Vektor "tatsächlich" ein Array, auf das Sie per Zeiger zugreifen können, um zu lesen oder zu schreiben. Das deckt also die meisten Fälle von Code ab, die Zeiger auf Arrays erwarten. Nur wenn dieser Code das Array zuweist oder freigibt, können Sie keinen Vektor verwenden.
Steve Jessop
@SteveJessop können Sie auf das interne Array zugreifen?
Luchian Grigore
1
@LuchianGrigore: vector.data()in C ++ 11 oder &vector.front()früher.
Mike Seymour
@Luchian: Sofern der Vektor nicht leer ist, können Sie einen Zeiger auf ein Element nehmen (und wenn er leer ist, können Sie einen Nullzeiger und eine Länge von 0 an jede sinnvoll geschriebene Funktion übergeben, die den Randfall von a akzeptiert Puffer mit der Größe Null). Der einzige Zweck der in C ++ 03 hinzugefügten Garantie für die Vektorkontiguität bestand darin, die Verwendung von Vektoren als Puffer durch zeigerorientierten Code zu ermöglichen.
Steve Jessop
1
@SteveJessop Und die Tatsache, dass viele Leute dachten, es sei sowieso garantiert, und es wurde als vorzuziehen angesehen, sie nicht zu enttäuschen.
James Kanze
4

Ich weiß, dass viele Leute auf std :: array für die Zuweisung von Arrays auf dem Stapel und std :: vector für den Heap hinweisen. Aber keiner scheint die nicht native Ausrichtung zu unterstützen. Wenn Sie einen numerischen Code verwenden, für den Sie SSE- oder VPX-Anweisungen verwenden möchten (daher eine Ausrichtung von 128 bzw. 256 Byte erforderlich ist), scheinen C-Arrays immer noch die beste Wahl zu sein.

gct
quelle
3

Ich würde sagen, Arrays sind immer noch nützlich, wenn Sie eine kleine statische Datenmenge speichern, warum nicht.

james82345
quelle
2

Der einzige Vorteil eines Arrays (natürlich in etwas eingeschlossen, das bei Bedarf automatisch seine Freigabe verwaltet) gegenüber dem, an das std::vectorich denken kann, ist, dass vectores den Besitz seiner Daten nicht weitergeben kann, es sei denn, Ihr Compiler unterstützt C ++ 11 und Verschiebungskonstruktoren.

Tadeusz Kopec
quelle
6
"Vektor kann das Eigentum an seinen Daten nicht übergeben" - ja, in C ++ 03 kann swap.
Steve Jessop
2

Arrays im C-Stil sind eine grundlegende Datenstruktur, daher wird es Fälle geben, in denen es besser ist, sie zu verwenden. Verwenden Sie für den allgemeinen Fall jedoch die erweiterten Datenstrukturen, die die Ecken der zugrunde liegenden Daten abrunden. Mit C ++ können Sie einige sehr interessante und nützliche Dinge mit dem Speicher tun, von denen viele mit einfachen Arrays funktionieren.

James Wynn
quelle
3
Wie sind Arrays im C-Stil grundlegender als std::arrays? Beide werden in vielen Fällen zu derselben Assembly kompiliert.
links um
1
Grundlegender darin, dass es grundlegender ist. Sie wissen, was ein Array tun wird. Std :: array weist möglicherweise Implementierungsprobleme auf, da es auf der Standardbibliothek basiert.
James Wynn
1
@ JamesWynn Nicht wirklich. std::arrayhat genau definierte Semantik auf statischen Arrays aufgebaut.
Konrad Rudolph
1

Sie sollten STL-Container intern verwenden, aber Sie sollten keine Zeiger auf solche Container zwischen verschiedenen Modulen übergeben, da Sie sonst in die Hölle der Abhängigkeit geraten. Beispiel:

std::string foo;
//  fill foo with stuff
myExternalOutputProc(foo.c_str());

ist eine sehr gute Lösung aber nicht

std::string foo;
//  fill foo with stuff
myExternalOutputProc(&foo);

Der Grund dafür ist, dass std :: string auf viele verschiedene Arten implementiert werden kann, ein String im C-Stil jedoch immer ein String im C-Stil ist.

user877329
quelle
Ich denke, Sie versuchen zu sagen: Verknüpfen Sie keinen unterschiedlichen Objektcode miteinander, wenn unterschiedliche Compiler / Implementierungen der Standardbibliothek verwendet wurden, um sie zu erstellen. Das stimmt sicherlich. In welcher Beziehung steht dies zur ursprünglichen Frage?
Jogojapan
Es ist nur ein Ratschlag, wann Arrays oder STL-Container verwendet werden sollen. Erstellen Sie Daten mithilfe eines Containers und übergeben Sie sie als Array. Für andere Daten, die Zeichenfolgen sind, hätten Sie so etwas wie myExternalOutputProc (foo.rawPointerGet (), foo.count ());
user877329
Diese Probleme treten jedoch nur auf, wenn Sie verschiedene Implementierungen der Standardbibliothek in demselben Projekt kombinieren. Das ist verrückt. In jedem normalen Code ist es vollkommen in Ordnung, beispielsweise einen Vektor als Referenz (oder in C ++ 11 zu verschieben) an eine Funktion zu übergeben.
Jogojapan
1
Ich mag zufällig Plug-Ins
user877329