Namensräume
Varianten
Aktionen

operator delete, operator delete[]

Von cppreference.com
< cpp‎ | memory‎ | new
 
 
Dienstprogramm-Bibliotheken
Sprachunterstützung
Typunterstützung (Basistypen, RTTI)
Bibliotheks-Feature-Test-Makros (C++20)
Programm-Dienstprogramme
Variadische Funktionen
Coroutine-Unterstützung (C++20)
Vertragsunterstützung (C++26)
Drei-Wege-Vergleich
(C++20)
(C++20)(C++20)(C++20)  
(C++20)(C++20)(C++20)

Allgemeine Hilfsmittel
Relationale Operatoren (in C++20 veraltet)
 
Speicherverwaltungsbibliothek
(nur Exposition*)
Algorithmen für uninitialisierten Speicher
(C++17)
(C++17)
(C++17)
Beschränkte uninitialisierte
Speicher-Algorithmen
C-Bibliothek

Allocatoren
Speicherressourcen
Unterstützung für Garbage Collection
(C++11)(bis C++23)
(C++11)(bis C++23)
(C++11)(bis C++23)
(C++11)(bis C++23)
(C++11)(bis C++23)
(C++11)(bis C++23)
Uninitialisierter Speicher
Explizites Lebenszeitmanagement
 
 
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.

1-12) Ersetzbare Funktionen zur Speicherfreigabe. Die Standardbibliothek stellt Standardimplementierungen für diese Funktionen bereit. Die Effekte der Standardimplementierungen finden Sie unten.
1-8) Aufgerufen von delete- und delete[]-Ausdrücken. Macht jeden nicht-null ptr ungültig.
9-12) Aufgerufen von Placement-new-Ausdrücken bei Initialisierungsfehlern. operator delete[] macht jeden nicht-null ptr ungültig.
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.
13,14) Aufgerufen von Placement-new-Ausdrücken, die eine nicht-allokierende Placement-Allocationsfunktion aufgerufen haben, wenn ein Teil der Initialisierung im Ausdruck durch eine Ausnahme beendet wird. Führt keine Aktion aus.
15-30) Benutzerdefinierte Funktionen zur Speicherfreigabe, aufgerufen von delete-, delete[]- und Placement-new-Ausdrücken.
27-30) Wenn definiert, führt der delete-Ausdruck den Destruktor für *ptr nicht aus, bevor ein Aufruf von operator delete erfolgt. Stattdessen wird die direkte Ausführung des Destruktors, z. B. durch ptr->~T();, zur Verantwortung dieses operator delete.

Ü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:

1) Wenn ptr null ist, geschieht nichts. Andernfalls wird der durch den früheren Aufruf von operator new alloziierte Speicher zurückgefordert.
2) Ruft operator delete(ptr) auf, als ob Überladung (1) den durch den früheren Aufruf von operator new[] allozierten Speicher zurückfordern könnte.
3) Identisch mit (1).
4) Ruft operator delete(ptr, al) auf, als ob Überladung (3) den durch den früheren Aufruf von operator new[] allozierten Speicher zurückfordern könnte.
5) Ruft operator delete(ptr) auf.
6) Ruft operator delete[](ptr) auf.
7) Ruft operator delete(ptr, al) auf.
8) Ruft operator delete[](ptr, al) auf.
9) Ruft operator delete(ptr) auf.
10) Ruft operator delete[](ptr) auf.
11) Ruft operator delete(ptr, al) auf.
12) Ruft operator delete[](ptr, al) auf.

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) [edit]
Allokationsfunktionen
(Funktion) [bearbeiten]
(veraltet in C++17)(entfernt in C++20)
gibt uninitialisierten Speicher frei
(Funktions-Template) [edit]
dealloziert zuvor allozierten Speicher
(function) [edit]