operator delete, operator delete[]
| Definiert in Header <new>
|
||
| Ersetzbare übliche Freigabefunktionen |
||
void operator delete ( void* ptr ) throw();
|
(1) | (bis C++11) |
void operator delete ( void* ptr ) noexcept;
|
(seit C++11) | |
void operator delete[]( void* ptr ) throw();
|
(2) | (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 Platzierungs-Freigabefunktionen |
||
void operator delete ( void* ptr, const std::nothrow_t& tag ) throw();
|
(9) | (bis C++11) |
void operator delete ( void* ptr, const std::nothrow_t& tag ) noexcept;
|
(seit C++11) | |
void operator delete[]( void* ptr, const std::nothrow_t& tag ) throw();
|
(10) | (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 allozierende Platzierungs-Freigabefunktionen |
||
void operator delete ( void* ptr, void* place ) throw();
|
(13) | (bis C++11) |
void operator delete ( void* ptr, void* place ) noexcept;
|
(seit C++11) | |
void operator delete[]( void* ptr, void* place ) throw();
|
(14) | (bis C++11) |
void operator delete[]( void* ptr, void* place ) noexcept;
|
(seit C++11) | |
| Benutzerdefinierte Platzierungs-Freigabefunktionen |
||
void operator delete ( void* ptr, args... );
|
(15) | |
void operator delete[]( void* ptr, args... );
|
(16) | |
| Klassenspezifische übliche Freigabefunktionen |
||
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 Platzierungs-Freigabefunktionen |
||
void T::operator delete ( void* ptr, args... );
|
(25) | |
void T::operator delete[]( void* ptr, args... );
|
(26) | |
| Klassenspezifische übliche destroying-Freigabefunktionen |
||
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 Speicher frei, der zuvor durch einen passenden operator new oder operator new[] alloziert wurde. Diese Freigabefunktionen werden von delete- und delete[]-Ausdrücken sowie von Platzierungs-newAusdrücken aufgerufen, um Speicher freizugeben, nachdem Objekte mit dynamischer Speicherdauer zerstört (oder fehlgeschlagene Konstruktion) wurden. Sie können auch mit regulärer Funktionsaufrufsyntax aufgerufen werden.
delete- und delete[]-Ausdrücken aufgerufen. Macht jeden Nicht-Null-ptr ungültig.new-Ausdrücken bei Initialisierungsfehler aufgerufen. operator delete[] macht jeden Nicht-Null-ptr ungültig.- Wenn
ptrkein Nullzeiger ist und eine der folgenden Bedingungen erfüllt ist, ist das Verhalten undefiniert:- Für
operator deleterepräsentiert der Wert vonptrnicht 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)) oderoperator new(std::size_t, std::align_val_t)(für Überladungen (3,7,11)) alloziert wurde, der nicht durch einen dazwischenliegenden Aufruf vonoperator deleteungültig gemacht wurde. - Für
operator delete[]repräsentiert der Wert vonptrnicht 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)) oderoperator new[](std::size_t, std::align_val_t)(für Überladungen (4,8,12)) alloziert wurde, der nicht durch einen dazwischenliegenden Aufruf vonoperator delete[]ungültig gemacht wurde.
- Für
new-Ausdrücken aufgerufen, die nicht allozierende Platzierungs-Allokationsfunktion aufgerufen haben, wenn ein Teil der Initialisierung im Ausdruck durch das Werfen einer Ausnahme beendet wird. Führt keine Aktion aus.delete-, delete[]- und Platzierungs-new-Ausdrücken aufgerufen werden.delete-Ausdrücke den Destruktor für *ptr nicht aus, bevor sie einen Aufruf von operator delete platzieren. Stattdessen wird der direkte Aufruf des Destruktors, wie z.B. durch ptr->~T();, zur Verantwortung dieses operator delete.Die Überladungen (1-8) werden in jeder Übersetzungseinheit implizit deklariert, auch wenn der <new>-Header nicht eingebunden ist.
Siehe delete-Ausdruck für die Kriterien zur Auswahl der Überladung.
Parameter
| ptr | - | Zeiger auf einen freizugebenden Speicherblock oder ein Nullzeiger |
| sz | - | die Größe, die an die passende Allokationsfunktion übergeben wurde |
| place | - | Zeiger, der als Platzierungsparameter im passenden Placement-New verwendet wurde |
| tag | - | Überladungsunterscheidungs-Tag, das zum Tag des nicht-werfenden operator new passt |
| al | - | Ausrichtung des allokierten Objekts oder Array-Elements |
| args | - | beliebige Parameter, die zu einer Platzierungs-Allokationsfunktion passen (können std::size_t und std::align_val_t enthalten) |
Exceptions
|
Alle Freigabefunktionen sind noexcept ( true ) , sofern in der Deklaration nicht anders angegeben. |
(seit C++11) |
Wenn eine Freigabefunktion durch Auslösen einer Exception beendet wird, ist das Verhalten undefiniert , selbst wenn sie mit noexcept ( false ) (seit C++11) deklariert ist.
Globale Ersetzungen
Überladungen ( 1-12 ) sind ersetzbar . Die Effekte der Standardversionen sind:
Globale
operator
-
new
/
delete
-Ersetzung:
#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 wie üblich im globalen Gültigkeitsbereich deklariert werden und werden von den entsprechenden Placement-Formen der new -Ausdrücke aufgerufen, wenn ein Konstruktor des zu allozierenden Objekts eine Exception wirft.
Die Platzierungsformen der Standardbibliothek von operator delete und operator delete [ ] ( 13,14 ) können nicht ersetzt werden und können nur angepasst werden, wenn der Platzierungs- new -Ausdruck nicht die :: new -Syntax verwendet hat, indem ein klassen-spezifischer Platzierungs-delete ( 25,26 ) mit übereinstimmender Signatur bereitgestellt wird: void T :: operator delete ( void * , void * ) oder void T :: operator delete [ ] ( void * , void * ) .
Klassenspezifische Überladungen
Deallocation-Funktionen ( 17-24 ) können als statische Member-Funktionen einer Klasse definiert werden. Diese Deallocation-Funktionen werden, sofern vorhanden, 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 , die 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 Deallocation-Funktion immer eine statische Member-Funktion.
Der delete-Ausdruck sucht nach dem Namen einer geeigneten Freigabefunktion, beginnend im Klassenbereich (die Array-Form sucht im Bereich der Array-Elementklasse) und setzt im globalen Bereich fort, falls keine Member gefunden werden, wie üblich. Beachten Sie, dass gemäß den Namenssuche-Regeln alle im Klassenbereich deklarierten Freigabefunktionen alle globalen Freigabefunktionen verbergen.
Wenn der statische Typ des zu löschenden Objekts von seinem dynamischen Typ abweicht (wie beim Löschen eines polymorphen Objekts durch einen Zeiger auf die Basisklasse), und wenn der Destruktor im statischen Typ virtuell ist, beginnt die Einzelobjekt-Form von delete mit der Suche nach dem Namen der Freigabefunktion ab dem Definitionspunkt des finalen Überschreibers seines virtuellen Destruktors. Unabhängig davon, welche Freigabefunktion zur Laufzeit ausgeführt würde, muss die statisch sichtbare Version von operator delete zugänglich sein, um kompilieren zu können. In anderen Fällen, wenn ein Array durch einen Zeiger auf die Basisklasse gelöscht wird, oder wenn durch einen Zeiger auf die Basisklasse mit nicht-virtuellem Destruktor gelöscht wird, ist das Verhalten undefiniert.
Wenn die Einzelargument-Überladung ( 17,18 ) nicht bereitgestellt wird, aber die größenbewusste Überladung mit std::size_t als zweitem Parameter ( 21,22 ) bereitgestellt wird, wird die größenbewusste Form für die normale Freigabe aufgerufen, und die C++-Laufzeit übergibt die Größe des freizugebenden Objekts als zweites Argument. Wenn beide Formen definiert sind, wird die größenunabhängige 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 fehlgeschlagene Placement- new -Ausdruck nach der entsprechenden Placement- delete -Funktion sucht, um sie aufzurufen, beginnt die Suche im Klassenbereich, bevor der globale Bereich untersucht wird, und sucht nach der Funktion mit der Signatur, die der Placement- new -Funktion entspricht:
#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 der klassenbezogene operator delete eine Template-Funktion ist, muss er den Rückgabetyp void haben, das erste Argument void * , und er muss zwei oder mehr Parameter besitzen. Mit anderen Worten: Nur Placement-Formen können Templates sein. Eine Template-Instanz ist niemals eine übliche Freigabefunktion, unabhängig von ihrer Signatur. Die Spezialisierung des Template-Operator-delete wird mittels Template-Argument-Deduktion ausgewählt.
Hinweise
Der Aufruf des klassen-spezifischen T :: operator delete bei einer polymorphen Klasse ist der einzige Fall, in dem eine statische Memberfunktion durch dynamische Bindung aufgerufen wird.
|
Die folgenden Funktionen müssen thread-sicher sein:
Aufrufe dieser Funktionen, die eine bestimmte Speichereinheit allozieren oder deallozieren, erfolgen in einer einzigen Gesamtordnung, und jeder solche Deallokationsaufruf happens-before dem nächsten Allokationsaufruf (falls vorhanden) in dieser Ordnung. |
(seit C++11) |
| Feature-Test Makro | Wert | Std | Funktion |
|---|---|---|---|
__cpp_sized_deallocation
|
201309L
|
(C++14) | Sized deallocation |
__cpp_impl_destroying_delete
|
201806L
|
(C++20) | Destroying operator delete (Compiler-Unterstützung) |
__cpp_lib_destroying_delete
|
201806L
|
(C++20) | Destroying operator delete (Bibliotheksunterstützung) |
Fehlerberichte
Die folgenden verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.
| DR | Angewendet auf | Verhalten wie veröffentlicht | Korrektes Verhalten |
|---|---|---|---|
| CWG 220 | C++98 | benutzerdefinierte Freigabefunktionen durften eine Exception werfen |
Werfen einer Exception aus einer Freigabefunktion
führt zu undefiniertem Verhalten |
| CWG 1438 | C++98 | jede Verwendung eines ungültigen Zeigerwerts war undefiniertes Verhalten | nur Dereferenzierung und Freigabe sind |
| LWG 206 | C++98 | Ersetzen von ( 2 ) beeinflusste nicht das Standardverhalten von ( 10 ) |
das Standardverhalten
ändert sich entsprechend |
| LWG 298 | C++98 | Ersetzen von ( 1 ) beeinflusste nicht das Standardverhalten von ( 9 ) |
das Standardverhalten
ändert sich entsprechend |
| LWG 404 | C++98 |
Ersetzungen der ersetzbaren Freigabefunktionen
konnten als inline deklariert werden |
verboten, keine Diagnose erforderlich |
| LWG 2458 | C++14 |
Überladungen mit
(
void
*
,
std::
size_t
,
const
std:: nothrow_t & ) waren spezifiziert, konnten aber nie aufgerufen werden |
entfernte überflüssige Überladungen |
Siehe auch
|
[static]
(C++23)
|
gibt zuvor von
operator new
beschafften Speicher frei
(öffentliche statische Mitgliedsfunktion von
std::generator<Ref,V,Allocator>::promise_type
)
|
|
Allokierungsfunktionen
(Funktion) |
|
|
(in C++17 veraltet)
(in C++20 entfernt)
|
gibt nicht initialisierten Speicher frei
(Funktionsschablone) |
|
gibt zuvor allokierten Speicher frei
(Funktion) |