Übergabe des Nullzeigers an die neue Platzierung

Die Standardplatzierungnew Der Operator wird in 18.6 [support.dynamic] ¶1 mit einer nicht auslösenden Ausnahmespezifikation deklariert:

void* operator new (std::size_t size, void* ptr) noexcept;

Diese Funktion macht nichts anderes alsreturn ptr; so ist es vernünftig, dass es so istnoexceptGemäß 5.3.4 [expr.new] ¶15 bedeutet dies jedoch, dass der Compiler überprüfen muss, ob er nicht null zurückgibt, bevor er den Konstruktor des Objekts aufruft:

-fünfzehn-
[Hinweis: Sofern eine Zuweisungsfunktion nicht mit einer Non-Throwing-Exception-Spezifikation (15.4) deklariert ist, weist dies auf einen Fehler bei der Speicherzuweisung durch das Auslösen von a hinstd::bad_alloc Ausnahme (Paragraph 15, 18.6.2.1); Andernfalls wird ein Zeiger ungleich Null zurückgegeben. Wenn die Zuweisungsfunktion mit einer nicht auslösenden Ausnahmespezifikation deklariert wird, gibt sie null zurück, um einen Fehler bei der Zuweisung von Speicher anzugeben, und andernfalls einen Zeiger ungleich null.- Ende der Notiz] Wenn die Zuweisungsfunktion null zurückgibt, wird die Initialisierung nicht durchgeführt, die Aufhebungsfunktion wird nicht aufgerufen, und der Wert des neuen Ausdrucks soll null sein.

Es scheint mir, dass (speziell für die Platzierungnew(nicht generell) Dieser Null-Check ist ein unglücklicher, wenn auch kleiner Leistungstreffer.

Ich habe einige Code-Fehler behoben, bei denen Platzierungnew wurde in einem sehr leistungsabhängigen Codepfad verwendet, um die Codegenerierung des Compilers zu verbessern, und die Überprüfung auf Null wurde in der Assembly beobachtet. Durch die Bereitstellung einer klassenspezifischen Platzierungnew Überladung, die mit einer auslösenden Ausnahmebedingungsspezifikation deklariert wurde (obwohl sie möglicherweise nicht auslösen kann), wurde entfernt, wodurch der Compiler auch kleineren Code für die umgebenden eingebetteten Funktionen generieren konnte. Das Ergebnis der Platzierungnew Funktionkönnte werfen, obwohl eskonnte nichtwar messbar besserer Code.

Ich habe mich also gefragt, ob die Nullprüfung wirklich für die Platzierung erforderlich istnew Fall. Die einzige Möglichkeit, null zurückzugeben, besteht darin, sie als null zu übergeben. Obwohl es möglich und anscheinend legal ist, zu schreiben:

void* ptr = nullptr;
Obj* obj = new (ptr) Obj();
assert( obj == nullptr );

Ich kann nicht erkennen, warum dies nützlich ist. Ich schlage vor, es wäre besser, wenn der Programmierer vor der Verwendung der Platzierung explizit auf null prüfen müsstenew z.B.

Obj* obj = ptr ? new (ptr) Obj() : nullptr;

Hat jemand jemals ein Praktikum gebraucht?new richtig mit dem Nullzeiger umgehen? (d. h. ohne eine explizite Überprüfung hinzuzufügen, dassptr ist ein gültiger Speicherort.)

Ich frage mich, ob es vernünftig wäre, die Weitergabe eines Nullzeigers an die Standardplatzierung zu verbietennew Funktion, und wenn nicht, ob es einen besseren Weg gibt, die unnötige Verzweigung zu vermeiden, als zu versuchen, dem Compiler mitzuteilen, dass der Wert nicht null ist, z.

void* ptr = getAddress();
(void) *(Obj*)ptr;   // inform the optimiser that dereferencing pointer is valid
Obj* obj = new (ptr) Obj();

Oder:

void* ptr = getAddress();
if (!ptr)
  __builtin_unreachable();  // same, but not portable
Obj* obj = new (ptr) Obj();

N.B. Ich bin der Meinung, dass diese Frage absichtlich mit Mikrooptimierung markiert istnicht Sie schlagen vor, die Platzierung zu überlastennew für alle Ihre Typen zur "Verbesserung" der Leistung. Dieser Effekt wurde in einem sehr spezifischen, leistungskritischen Fall festgestellt und basiert auf Profilerstellung und Messung.

Aktualisieren: DR 1748 macht es undefiniert, einen Nullzeiger bei der Platzierung neu zu verwenden, sodass Compiler nicht mehr für die Überprüfung erforderlich sind.

Antworten auf die Frage(1)

Ihre Antwort auf die Frage