operator delete, operator delete[]
| Definiert im Header <new> |
||
| Ersetzbare Funktionen zur Speicherfreigabe |
||
| (1) | ||
void operator delete ( void* ptr ) throw(); |
(bis C++11) | |
| void operator delete ( void* ptr ) noexcept; |
(seit C++11) | |
| (2) | ||
void operator delete[]( void* ptr ) throw(); |
(bis C++11) | |
| void operator delete[]( void* ptr ) noexcept; |
(seit C++11) | |
void operator delete ( void* ptr, std::align_val_t al ) noexcept; |
(3) | (seit C++17) |
void operator delete[]( void* ptr, std::align_val_t al ) noexcept; |
(4) | (seit C++17) |
void operator delete ( void* ptr, std::size_t sz ) noexcept; |
(5) | (seit C++14) |
void operator delete[]( void* ptr, std::size_t sz ) noexcept; |
(6) | (seit C++14) |
void operator delete ( void* ptr, std::size_t sz, std::align_val_t al ) noexcept; |
(7) | (seit C++17) |
void operator delete[]( void* ptr, std::size_t sz, std::align_val_t al ) noexcept; |
(8) | (seit C++17) |
| Ersetzbare Funktionen zur Speicherfreigabe durch Placement |
||
| (9) | ||
void operator delete ( void* ptr, const std::nothrow_t& tag ) throw(); |
(bis C++11) | |
| void operator delete ( void* ptr, const std::nothrow_t& tag ) noexcept; |
(seit C++11) | |
| (10) | ||
void operator delete[]( void* ptr, const std::nothrow_t& tag ) throw(); |
(bis C++11) | |
| void operator delete[]( void* ptr, const std::nothrow_t& tag ) noexcept; |
(seit C++11) | |
void operator delete ( void* ptr, std::align_val_t al, const std::nothrow_t& tag ) noexcept; |
(11) | (seit C++17) |
void operator delete[]( void* ptr, std::align_val_t al, const std::nothrow_t& tag ) noexcept; |
(12) | (seit C++17) |
| Nicht-allokierende Placement-Funktionen zur Speicherfreigabe |
||
| (13) | ||
void operator delete ( void* ptr, void* place ) throw(); |
(bis C++11) | |
| void operator delete ( void* ptr, void* place ) noexcept; |
(seit C++11) | |
| (14) | ||
void operator delete[]( void* ptr, void* place ) throw(); |
(bis C++11) | |
| void operator delete[]( void* ptr, void* place ) noexcept; |
(seit C++11) | |
| Benutzerdefinierte Placement-Funktionen zur Speicherfreigabe |
||
void operator delete ( void* ptr, args... ); |
(15) | |
void operator delete[]( void* ptr, args... ); |
(16) | |
| Klassenspezifische Funktionen zur Speicherfreigabe |
||
void T::operator delete ( void* ptr ); |
(17) | |
void T::operator delete[]( void* ptr ); |
(18) | |
void T::operator delete ( void* ptr, std::align_val_t al ); |
(19) | (seit C++17) |
void T::operator delete[]( void* ptr, std::align_val_t al ); |
(20) | (seit C++17) |
void T::operator delete ( void* ptr, std::size_t sz ); |
(21) | |
void T::operator delete[]( void* ptr, std::size_t sz ); |
(22) | |
void T::operator delete ( void* ptr, std::size_t sz, std::align_val_t al ); |
(23) | (seit C++17) |
void T::operator delete[]( void* ptr, std::size_t sz, std::align_val_t al ); |
(24) | (seit C++17) |
| Klassenspezifische Placement-Funktionen zur Speicherfreigabe |
||
void T::operator delete ( void* ptr, args... ); |
(25) | |
void T::operator delete[]( void* ptr, args... ); |
(26) | |
| Klassenspezifische Funktionen zur Speicherfreigabe mit Zerstörung |
||
void T::operator delete( T* ptr, std::destroying_delete_t ); |
(27) | (seit C++20) |
void T::operator delete( T* ptr, std::destroying_delete_t, std::align_val_t al ); |
(28) | (seit C++20) |
void T::operator delete( T* ptr, std::destroying_delete_t, std::size_t sz ); |
(29) | (seit C++20) |
void T::operator delete( T* ptr, std::destroying_delete_t, std::size_t sz, std::align_val_t al ); |
(30) | (seit C++20) |
Gibt zuvor von einem passenden operator new oder operator new[] allozierten Speicher frei. Diese Funktionen zur Speicherfreigabe werden von delete- und delete[]-Ausdrücken sowie von Placement-new-Ausdrücken aufgerufen, um Speicher nach dem Zerstören (oder fehlgeschlagenen Erstellen) von Objekten mit dynamischer Speicherdauer freizugeben. Sie können auch mit regulärer Funktionsaufrufsyntax aufgerufen werden.
- Wenn ptr kein Nullzeiger ist und eine der folgenden Bedingungen erfüllt ist, ist das Verhalten undefiniert
- Für operator delete repräsentiert der Wert von ptr nicht die Adresse eines Speicherblocks, der durch einen früheren Aufruf von (möglicherweise ersetztem) operator new(std::size_t) (für Überladungen (1,5,9)) oder operator new(std::size_t, std::align_val_t) (für Überladungen (3,7,11)) zugewiesen wurde, der nicht durch einen dazwischenliegenden Aufruf von operator delete ungültig gemacht wurde.
- Für operator delete[] repräsentiert der Wert von ptr nicht die Adresse eines Speicherblocks, der durch einen früheren Aufruf von (möglicherweise ersetztem) operator new[](std::size_t) (für Überladungen (2,6,10)) oder operator new[](std::size_t, std::align_val_t) (für Überladungen (4,8,12)) zugewiesen wurde, der nicht durch einen dazwischenliegenden Aufruf von operator delete[] ungültig gemacht wurde.
Überladungen (1-8) werden in jeder Translation Unit implizit deklariert, auch wenn die <new>-Headerdatei nicht eingebunden ist.
Siehe delete-Ausdruck für die Kriterien zur Auswahl der Überladung.
Inhalt |
[edit] Parameter
| ptr | - | Zeiger auf einen zu deallokierenden Speicherblock oder ein Nullzeiger |
| sz | - | Die Größe, die an die passende Allokationsfunktion übergeben wurde |
| place | - | Zeiger, der als Placement-Parameter im passenden Placement-new verwendet wird |
| tag | - | Überladungs-Disambiguierungs-Tag, passend zum Tag, das von nicht-werfendem Operator new verwendet wird |
| al | - | Ausrichtung des allozierten Objekts oder Array-Elements |
| args | - | beliebige Parameter, die einer Placement-Allocationsfunktion entsprechen (können std::size_t und std::align_val_t beinhalten) |
[edit] Ausnahmen
|
Alle Funktionen zur Speicherfreigabe sind noexcept(true), sofern in der Deklaration nicht anders angegeben. |
(seit C++11) |
Wenn eine Funktion zur Speicherfreigabe durch das Werfen einer Ausnahme beendet wird, ist das Verhalten undefiniert, auch wenn sie mit noexcept(false) deklariert ist(seit C++11).
[edit] Globale Ersetzungen
Überladungen (1-12) sind ersetzbar. Die Effekte der Standardversionen sind:
Globale Ersetzung von operator new/delete
#include <cstdio> #include <cstdlib> #include <new> // no inline, required by [replacement.functions]/3 void* operator new(std::size_t sz) { std::printf("1) new(size_t), size = %zu\n", sz); if (sz == 0) ++sz; // avoid std::malloc(0) which may return nullptr on success if (void *ptr = std::malloc(sz)) return ptr; throw std::bad_alloc{}; // required by [new.delete.single]/3 } // no inline, required by [replacement.functions]/3 void* operator new[](std::size_t sz) { std::printf("2) new[](size_t), size = %zu\n", sz); if (sz == 0) ++sz; // avoid std::malloc(0) which may return nullptr on success if (void *ptr = std::malloc(sz)) return ptr; throw std::bad_alloc{}; // required by [new.delete.single]/3 } void operator delete(void* ptr) noexcept { std::puts("3) delete(void*)"); std::free(ptr); } void operator delete(void* ptr, std::size_t size) noexcept { std::printf("4) delete(void*, size_t), size = %zu\n", size); std::free(ptr); } void operator delete[](void* ptr) noexcept { std::puts("5) delete[](void* ptr)"); std::free(ptr); } void operator delete[](void* ptr, std::size_t size) noexcept { std::printf("6) delete[](void*, size_t), size = %zu\n", size); std::free(ptr); } int main() { int* p1 = new int; delete p1; int* p2 = new int[10]; // guaranteed to call the replacement in C++11 delete[] p2; }
Mögliche Ausgabe
// Compiled with GCC-5 in C++17 mode to obtain the following: 1) op new(size_t), size = 4 4) op delete(void*, size_t), size = 4 2) op new[](size_t), size = 40 5) op delete[](void* ptr)
Überladungen von operator delete und operator delete[] mit zusätzlichen benutzerdefinierten Parametern ("Placement-Formen", (15,16)) können im globalen Scope wie üblich deklariert werden und werden von den passenden Placement-Formen von new-Ausdrücken aufgerufen, wenn ein Konstruktor des allozierten Objekts eine Ausnahme wirft.
Die Standardbibliotheks-Placement-Formen von operator delete und operator delete[] (13,14) können nicht ersetzt werden und können nur angepasst werden, wenn der Placement-new-Ausdruck nicht die ::new-Syntax verwendet hat, indem eine klassenspezifische Placement-delete-Funktion (25,26) mit passender Signatur bereitgestellt wird: void T::operator delete(void*, void*) oder void T::operator delete[](void*, void*).
[edit] Klassenspezifische Überladungen
Funktionen zur Speicherfreigabe (17-24) können als statische Member-Funktionen einer Klasse definiert werden. Diese Funktionen zur Speicherfreigabe, sofern vorhanden, werden von delete-Ausdrücken beim Löschen von Objekten (17,19,21) und Arrays (18,20,22) dieser Klasse aufgerufen, es sei denn, der delete-Ausdruck verwendete die Form ::delete, welche die klassenbezogene Suche umgeht. Das Schlüsselwort static ist für diese Funktionsdeklarationen optional: Unabhängig davon, ob das Schlüsselwort verwendet wird oder nicht, ist die Funktion zur Speicherfreigabe immer eine statische Member-Funktion.
Der delete-Ausdruck sucht nach dem Namen der passenden Funktion zur Speicherfreigabe, beginnend im Klassenscope (die Array-Form sucht im Scope der Klasse des Array-Elements) und fährt bis zum globalen Scope fort, wenn keine Member gefunden werden, wie üblich. Beachten Sie, dass gemäß den Namenssuchregeln alle im Klassenscope deklarierten Funktionen zur Speicherfreigabe alle globalen Funktionen zur Speicherfreigabe verbergen.
Wenn der statische Typ des zu löschenden Objekts vom dynamischen Typ abweicht (z. B. beim Löschen eines polymorphen Objekts über einen Zeiger auf die Basisklasse) und der Destruktor im statischen Typ virtuell ist, beginnt die Suche nach dem Namen der Funktion zur Speicherfreigabe der einzelnen Objektform von delete am Punkt der Definition des finalen Overriders seines virtuellen Destruktors. Unabhängig davon, welche Funktion zur Speicherfreigabe zur Laufzeit ausgeführt würde, muss die statisch sichtbare Version von operator delete zugänglich sein, damit sie kompiliert wird. In anderen Fällen, beim Löschen eines Arrays über einen Zeiger auf die Basisklasse oder beim Löschen über einen Zeiger auf die Basisklasse mit nicht-virtuellem Destruktor, ist das Verhalten undefiniert.
Wenn die Überladung mit einem einzelnen Argument (17,18) nicht bereitgestellt wird, aber die größenbewusste Überladung, die std::size_t als zweiten Parameter nimmt (21,22), bereitgestellt wird, wird die größenbewusste Form für die normale Speicherfreigabe aufgerufen, und die C++-Laufzeit übergibt die Größe des zu deallokierenden Objekts als zweites Argument. Wenn beide Formen definiert sind, wird die größenunbewusste Version aufgerufen.
#include <cstddef> #include <iostream> // sized class-specific deallocation functions struct X { static void operator delete(void* ptr, std::size_t sz) { std::cout << "custom delete for size " << sz << '\n'; ::operator delete(ptr); } static void operator delete[](void* ptr, std::size_t sz) { std::cout << "custom delete for size " << sz << '\n'; ::operator delete[](ptr); } }; int main() { X* p1 = new X; delete p1; X* p2 = new X[10]; delete[] p2; }
Mögliche Ausgabe
custom delete for size 1 custom delete for size 18
Überladungen von operator delete und operator delete[] mit zusätzlichen benutzerdefinierten Parametern ("Placement-Formen", (25,26)) können ebenfalls als Klassenmember definiert werden. Wenn der fehlerhafte Placement-new-Ausdruck nach der entsprechenden Placement-delete-Funktion sucht, um sie aufzurufen, beginnt die Suche im Klassenscope, bevor der globale Scope untersucht wird, und sucht nach der Funktion mit der passenden Signatur des Placement-new.
#include <cstddef> #include <iostream> #include <stdexcept> struct X { X() { throw std::runtime_error("X(): std::runtime_error"); } // custom placement new static void* operator new(std::size_t sz, bool b) { std::cout << "custom placement new called, b = " << b << '\n'; return ::operator new(sz); } // custom placement delete static void operator delete(void* ptr, bool b) { std::cout << "custom placement delete called, b = " << b << '\n'; ::operator delete(ptr); } }; int main() { try { [[maybe_unused]] X* p1 = new (true) X; } catch (const std::exception& ex) { std::cout << ex.what() << '\n'; } }
Ausgabe
custom placement new called, b = 1 custom placement delete called, b = 1 X(): std::runtime_error
Wenn operator delete auf Klassenebene eine Vorlagenfunktion ist, muss sie den Rückgabetyp void, das erste Argument void* haben und mindestens zwei Parameter besitzen. Mit anderen Worten, nur Placement-Formen können Vorlagen sein. Eine Vorlageninstanz ist niemals eine reguläre Funktion zur Speicherfreigabe, unabhängig von ihrer Signatur. Die Spezialisierung des Vorlagen-Operator-delete wird mittels Template-Argument-Deduction ausgewählt.
[edit] Hinweise
Der Aufruf von klassenspezifischem T::operator delete für eine polymorphe Klasse ist der einzige Fall, in dem eine statische Member-Funktion über dynamische Dispatch aufgerufen wird.
|
Die folgenden Funktionen sind Thread-sicher erforderlich
Aufrufe dieser Funktionen, die eine bestimmte Speichereinheit zuweisen oder freigeben, erfolgen in einer einzigen Gesamtordnung, und jeder solche Freigabeaufruf happens-before die nächste Zuweisung (falls vorhanden) in dieser Ordnung. |
(seit C++11) |
| Feature-Test-Makro | Wert | Std | Feature |
|---|---|---|---|
__cpp_sized_deallocation |
201309L |
(C++14) | Größenbasierte Speicherfreigabe |
__cpp_impl_destroying_delete |
201806L |
(C++20) | Zerstörender Operator delete (Compiler-Unterstützung) |
__cpp_lib_destroying_delete |
201806L |
(C++20) | Zerstörender Operator delete (Bibliotheksunterstützung) |
[edit] Defect Reports
Die folgenden Verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.
| DR | angewendet auf | Verhalten wie veröffentlicht | Korrigiertes Verhalten |
|---|---|---|---|
| CWG 220 | C++98 | benutzerdefinierte Funktionen zur Speicherfreigabe durften werfen | Werfen aus einer Funktion zur Speicherfreigabe führt zu undefiniertem Verhalten |
| CWG 1438 | C++98 | jede Verwendung eines ungültigen Zeigerwerts war undefiniertes Verhalten | nur Indirektion und Deallokation sind |
| LWG 206 | C++98 | Ersetzen von (2) hatte keinen Einfluss auf das Standardverhalten von (10) | das Standardverhalten ändert sich entsprechend |
| LWG 298 | C++98 | Ersetzen von (1) hatte keinen Einfluss auf das Standardverhalten von (9) | das Standardverhalten ändert sich entsprechend |
| LWG 404 | C++98 | Ersetzungen der ersetzbaren Speicherfreigabe Funktionen konnten inline deklariert werden |
verboten, keine Diagnose erforderlich |
| LWG 2458 | C++14 | Überladungen, die (void*, std::size_t, const std::nothrow_t&) spezifizierten, aber nie aufgerufen werden konnten |
entfernte überflüssige Überladungen |
[edit] Siehe auch
| [static] (C++23) |
deallokiert Speicher, der zuvor von operator new erhalten wurde(public static member function of std::generator<Ref,V,Allocator>::promise_type) |
| Allokationsfunktionen (Funktion) | |
| (veraltet in C++17)(entfernt in C++20) |
gibt uninitialisierten Speicher frei (Funktions-Template) |
| dealloziert zuvor allozierten Speicher (function) |