C++ neu int[0] — wird es Speicher zuweisen?

Lesezeit: 8 Minuten

Eine einfache Test-App:

cout << new int[0] << endl;

Ausgänge:

0x876c0b8

Scheint also zu funktionieren. Was sagt die Norm dazu? Ist es immer legal, leere Speicherblöcke zu “zuordnen”?

  • +1 Sehr interessante Frage – obwohl ich mir nicht sicher bin, wie wichtig es im echten Code ist.

    – Zifre

    6. Juli 2009 um 13:46 Uhr

  • @Zifre: Ich frage aus Neugier, aber es könnte in der realen Welt von Bedeutung sein, z. B. wenn die Größe der zugewiesenen Speicherblöcke auf irgendeine Weise berechnet wird und das Ergebnis der Berechnung möglicherweise Null ist, dann besteht keine direkte Notwendigkeit, Ausnahmen hinzuzufügen Blöcke der Größe Null nicht zuzuweisen. Weil sie ohne Fehler zugewiesen und gelöscht werden sollten (wenn nur der Block der Größe Null nicht dereferenziert wird). Im Allgemeinen gibt dies also eine breitere Abstraktion dessen, was ein Speicherblock ist.

    anon

    6. Juli 2009 um 13:59 Uhr

  • @emg-2: In Ihrer Beispielsituation wäre es eigentlich egal, weil löschen[] ist auf einem NULL-Zeiger vollkommen legal :-).

    – Evan Teran

    6. Juli 2009 um 14:01 Uhr

  • Es ist nur tangential verwandt – also kommentiere ich hier -, aber C++ stellt in vielerlei Hinsicht sicher, dass unterschiedliche Objekte eindeutige Adressen haben … selbst wenn sie nicht explizit Speicher benötigen. Ein verwandtes Experiment wäre, die Größe einer leeren Struktur zu überprüfen. Oder ein Array dieser Struktur.

    – Drew Dormann

    6. Juli 2009 um 15:47 Uhr

  • Um Shmooptys Kommentar weiter auszuführen: Besonders wenn mit Templates programmiert wird (z. B. Policy-Klassen-Templates wie std::allocator), ist es in C++ üblich, Objekte der Größe Null zu haben. Allgemeiner Code muss solche Objekte möglicherweise dynamisch zuweisen und Zeiger auf sie verwenden, um die Objektidentität zu vergleichen. Aus diesem Grund gibt der Operator new() eindeutige Zeiger für Anfragen mit der Größe null zurück. Obwohl dies wohl weniger wichtig/üblich ist, gilt die gleiche Argumentation für die Array-Zuweisung und den neuen Operator[]().

    – Trevor Robinson

    13. Januar 2010 um 20:46 Uhr

C neu int0 wird es Speicher zuweisen
Faisal Vali

Ab 5.3.4/7

Wenn der Wert des Ausdrucks in einem direct-new-declarator Null ist, wird die Zuordnungsfunktion aufgerufen, um ein Array ohne Elemente zuzuweisen.

Ab 3.7.3.1/2

Die Auswirkung der Dereferenzierung eines Zeigers, der als Anforderung für die Größe Null zurückgegeben wird, ist nicht definiert.

Ebenfalls

Auch wenn die Größe des Platzes gefragt ist [by new] Null ist, kann die Anforderung fehlschlagen.

Das heißt, Sie können es tun, aber Sie können den Speicher, den Sie erhalten, nicht legal (in einer wohldefinierten Weise auf allen Plattformen) dereferenzieren – Sie können ihn nur an array delete übergeben – und Sie sollten ihn löschen.

Hier ist eine interessante Fußnote (dh kein normativer Teil der Norm, sondern zu Erläuterungszwecken enthalten) an den Satz von 3.7.3.1/2 angehängt

[32. The intent is to have operator new() implementable by calling malloc() or calloc(), so the rules are substantially the same. C++ differs from C in requiring a zero request to return a non-null pointer.]

  • Ich erhalte ein Speicherleck, wenn ich nicht lösche. Wird es erwartet? Zumindest habe ich nicht erwartet.

    – EralpB

    10. März 2014 um 13:46 Uhr

  • @EralpB: Im Gegenteil, selbst wenn Ihre Anfrage Null ist, erfolgt diese Zuweisung auf dem Heap, wobei eine Anfrage mehrere Buchhaltungsvorgänge impliziert, wie das Zuweisen und Initialisieren von Heap Guards vor und nach der vom Zuordner angegebenen Zone, das Einfügen in Freelists oder andere komplexe schreckliche Strukturen. Es zu befreien bedeutet, die Buchhaltung rückwärts zu führen.

    – v.oddou

    13. Juni 2014 um 12:18 Uhr

  • @EralpB Ja, ich denke, Sie können jedes Mal mit einem Speicherleck rechnen, wenn Sie a nicht ausgleichen new[] mit einer delete[] – unabhängig von der Größe. Vor allem, wenn Sie anrufen new[i] Sie benötigen etwas mehr Speicher als den, den Sie zuweisen möchten, um die Größe des Arrays zu speichern (das später von verwendet wird delete[] beim Auflösen)

    – pqnet

    20. Oktober 2017 um 15:51 Uhr


  • Da außerdem das Inkrementieren eines Zeigers, der auf ein Element nach dem letzten Element in einem Speicherblock zeigt, zulässig ist, sollte es zulässig sein, einen Zeiger zu inkrementieren, der auf diesen Speicherblock der Größe Null zeigt.

    – ghd

    7. März um 10:11 Uhr


Ja, es ist legal, ein solches Array der Größe Null zuzuweisen. Aber Sie müssen es auch löschen.

  • Hast du dafür ein Zitat? Wir alle wissen das int ar[0]; ist illegal warum ist neu OK?

    – Motti

    6. Juli 2009 um 13:47 Uhr

  • Es ist interessant, dass C++ nicht so stark ist, wenn es darum geht, Objekte der Größe Null zu verbieten. Denken Sie an die Optimierung der leeren Basisklasse: Auch hier kann ein leeres Unterobjekt der Basisklasse die Größe Null haben. Im Gegensatz dazu unternimmt der C-Standard große Anstrengungen, um sicherzustellen, dass niemals Objekte der Größe Null erstellt werden: Bei der Definition von malloc(0) heißt es beispielsweise, dass der Effekt darin besteht, malloc mit einem Argument ungleich Null auszuführen. Und instruieren { …; T n[]; }; Wenn dem Array (FAM) kein Speicherplatz zugewiesen ist, verhält es sich so, als hätte “n” ein Element. (In beiden Fällen ist die Verwendung des Objekts in irgendeiner Weise UB, wie xn[0])

    – Johannes Schaub – litb

    6. Juli 2009 um 16:25 Uhr

  • Ich denke sizeof (type) wird erwartet, dass es niemals Null zurückgibt. Siehe zum Beispiel: stackoverflow.com/questions/2632021/can-sizeof-return-0-zero

    – pqnet

    20. Oktober 2017 um 15:54 Uhr

  • Sogar die sogenannte “leere Basisklassenoptimierung” ist nur relevant, weil darauf bestanden wird, dass alle Objekte (im Gegensatz zu allen Bytes innerhalb von Objekten) eindeutige Adressen haben müssen. C++ hätte einfacher gemacht werden können, wenn Code, der sich tatsächlich um Objekte mit eindeutigen Adressen kümmert, erforderlich wäre, um sicherzustellen, dass sie eine Größe ungleich Null haben.

    – Superkatze

    27. Juni 2018 um 21:26 Uhr

Was sagt die Norm dazu? Ist es immer legal, leere Speicherblöcke zu “zuordnen”?

Jedes Objekt hat eine eindeutige Identität, dh eine eindeutige Adresse, was eine Länge ungleich Null impliziert (die tatsächliche Speichermenge wird stillschweigend erhöht, wenn Sie nach Null Bytes fragen).

Wenn Sie mehr als eines dieser Objekte zugewiesen haben, werden Sie feststellen, dass sie unterschiedliche Adressen haben.

  • “Jedes Objekt hat eine eindeutige Identität, dh eine eindeutige Adresse, was eine Länge ungleich Null impliziert” – wahr, aber falsch. Das Objekt hat eine Adresse, aber der Zeiger auf das Objekt kann auf einen zufälligen Speicher zeigen. “Die tatsächliche Speichermenge wird stillschweigend erhöht, wenn Sie nach null Bytes fragen” – nicht sicher. operator [] speichert auch die Größe des Arrays irgendwo (siehe isocpp.org/wiki/faq/freestore-mgmt#num-elems-in-new-array). Wenn also die Implementierung die Byteanzahl mit den Daten zuweist, könnte sie einfach die Byteanzahl und 0 Bytes für Daten zuweisen und einen 1-nach-letzten-Zeiger zurückgeben.

    – Ross

    13. April 2016 um 12:31 Uhr

  • Eine Länge des zugewiesenen Speichers ungleich Null, keine Länge des nutzbaren Speichers ungleich Null. Mein Punkt war, dass zwei Zeiger auf zwei unterschiedliche Objekte nicht auf dieselbe Adresse zeigen sollten.

    – ChrisW

    13. April 2016 um 13:50 Uhr


  • Der Standard (open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf) sagt zwar (3.7.4.1/2) dass verschiedene Aufrufe an operator new[] sollte unterschiedliche Zeiger zurückgeben. Übrigens, die new expression hat einige zusätzliche Regeln (5.3.4). Ich konnte keinen Hinweis darauf finden new mit 0 größe ist eigentlich erforderlich irgendetwas zuordnen. Entschuldigung, ich habe abgelehnt, weil ich finde, dass Ihre Antwort die Fragen nicht beantwortet, aber einige kontroverse Aussagen enthält.

    – Ross

    13. April 2016 um 15:31 Uhr

  • @Steed Der Speicher zum Speichern der Länge des Blocks kann implizit mithilfe des Adressraums berechnet werden. Für Arrays der Größe Null könnte es beispielsweise für die möglich sein new[] Implementierung, um Adressen in einem Bereich zurückzugeben, in dem kein dynamischer Speicher zugeordnet ist, wodurch nicht wirklich Speicher verwendet wird (während Adressraum verwendet wird)

    – pqnet

    20. Oktober 2017 um 16:00 Uhr

  • @pqnet: Eine qualitativ hochwertige Implementierung sollte eine unbegrenzte Anzahl von Neu-/Löschzyklen zulassen, oder nicht? Auf einer Plattform mit 64-Bit-Zeigern könnte es vernünftig sein zu sagen, dass ein Computer, der a while(!exitRequested) { char *p = new char[0]; delete [] p; } -Schleife ohne Recycling-Zeiger würde zu Staub zerfallen, bevor ihr möglicherweise der Adressraum ausgeht, aber auf einer Plattform mit 32-Bit-Zeigern wäre dies eine weitaus weniger vernünftige Annahme.

    – Superkatze

    27. Juni 2018 um 21:30 Uhr


1647066614 171 C neu int0 wird es Speicher zuweisen
Evan Teran

Ja, es ist völlig legal, a zuzuweisen 0 großer Block mit new. Sie können einfach nichts Nützliches damit anfangen, da es keine gültigen Daten gibt, auf die Sie zugreifen können. int[0] = 5; ist illegal.

Ich glaube jedoch, dass der Standard Dinge zulässt wie malloc(0) zurückgeben NULL.

Das müssen Sie noch delete [] welchen Zeiger Sie auch von der Zuweisung zurückbekommen.

Seltsamerweise erfordert C++, dass der Operator new einen legitimen Zeiger zurückgibt, selbst wenn null Bytes angefordert werden. (Das Erfordernis dieses seltsam klingenden Verhaltens vereinfacht die Dinge an anderer Stelle in der Sprache.)

ich fand Gültige dritte Ausgabe von C++ so in “Punkt 51: Konventionen beim Schreiben von Neu und Löschen einhalten”.

picture?type=large
Shi Jieming

Ich garantiere Ihnen, dass neue int[0] kostet Sie zusätzlichen Speicherplatz, da ich es getestet habe.

Zum Beispiel die Speichernutzung von

int **arr = new int*[1000000000];

ist deutlich kleiner als

int **arr = new int*[1000000000];
for(int i =0; i < 1000000000; i++) {
    arr[i]=new int[0];
}

Die Speichernutzung des zweiten Code-Snippets abzüglich der des ersten Code-Snippets ist der Speicher, der für die zahlreichen neuen int verwendet wird[0].

992910cookie-checkC++ neu int[0] — wird es Speicher zuweisen?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy