operator delete, operator delete[]
| ヘッダ <new> で定義 |
||
| 再配置可能な標準的な非割り当て関数 |
||
| (1) | ||
void operator delete ( void* ptr ) throw(); |
(C++11まで) | |
| void operator delete ( void* ptr ) noexcept; |
(C++11以降) | |
| (2) | ||
void operator delete[]( void* ptr ) throw(); |
(C++11まで) | |
| void operator delete[]( void* ptr ) noexcept; |
(C++11以降) | |
void operator delete ( void* ptr, std::align_val_t al ) noexcept; |
(3) | (C++17以降) |
void operator delete[]( void* ptr, std::align_val_t al ) noexcept; |
(4) | (C++17以降) |
void operator delete ( void* ptr, std::size_t sz ) noexcept; |
(5) | (C++14以降) |
void operator delete[]( void* ptr, std::size_t sz ) noexcept; |
(6) | (C++14以降) |
void operator delete ( void* ptr, std::size_t sz, std::align_val_t al ) noexcept; |
(7) | (C++17以降) |
void operator delete[]( void* ptr, std::size_t sz, std::align_val_t al ) noexcept; |
(8) | (C++17以降) |
| 配置配置解除関数 |
||
| (9) | ||
void operator delete ( void* ptr, const std::nothrow_t& tag ) throw(); |
(C++11まで) | |
| void operator delete ( void* ptr, const std::nothrow_t& tag ) noexcept; |
(C++11以降) | |
| (10) | ||
void operator delete[]( void* ptr, const std::nothrow_t& tag ) throw(); |
(C++11まで) | |
| void operator delete[]( void* ptr, const std::nothrow_t& tag ) noexcept; |
(C++11以降) | |
void operator delete ( void* ptr, std::align_val_t al, const std::nothrow_t& tag ) noexcept; |
(11) | (C++17以降) |
void operator delete[]( void* ptr, std::align_val_t al, const std::nothrow_t& tag ) noexcept; |
(12) | (C++17以降) |
| 非配置配置解除関数 |
||
| (13) | ||
void operator delete ( void* ptr, void* place ) throw(); |
(C++11まで) | |
| void operator delete ( void* ptr, void* place ) noexcept; |
(C++11以降) | |
| (14) | ||
void operator delete[]( void* ptr, void* place ) throw(); |
(C++11まで) | |
| void operator delete[]( void* ptr, void* place ) noexcept; |
(C++11以降) | |
| ユーザー定義配置解除関数 |
||
void operator delete ( void* ptr, args... ); |
(15) | |
void operator delete[]( void* ptr, args... ); |
(16) | |
| クラス固有の標準的な非配置解除関数 |
||
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) | (C++17以降) |
void T::operator delete[]( void* ptr, std::align_val_t al ); |
(20) | (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) | (C++17以降) |
void T::operator delete[]( void* ptr, std::size_t sz, std::align_val_t al ); |
(24) | (C++17以降) |
| クラス固有の配置解除関数 |
||
void T::operator delete ( void* ptr, args... ); |
(25) | |
void T::operator delete[]( void* ptr, args... ); |
(26) | |
| クラス固有の標準破壊解除関数 |
||
void T::operator delete( T* ptr, std::destroying_delete_t ); |
(27) | (C++20以降) |
void T::operator delete( T* ptr, std::destroying_delete_t, std::align_val_t al ); |
(28) | (C++20以降) |
void T::operator delete( T* ptr, std::destroying_delete_t, std::size_t sz ); |
(29) | (C++20以降) |
void T::operator delete( T* ptr, std::destroying_delete_t, std::size_t sz, std::align_val_t al ); |
(30) | (C++20以降) |
動的な記憶域期間を持つオブジェクトの構築(または構築失敗)後に、delete および delete[] 式 や 配置 new 式によって呼び出され、以前に割り当てられたメモリを解放します。通常の関数呼び出し構文を使用して呼び出すこともできます。
- ptr がヌルポインタではなく、かつ以下のいずれかの条件が満たされている場合、動作は未定義です。
- operator delete については、ptr の値が、以前の(置換された可能性のある)operator new(std::size_t)(オーバーロード (1,5,9) の場合)または operator new(std::size_t, std::align_val_t)(オーバーロード (3,7,11) の場合)によって割り当てられたメモリブロックのアドレスを表しておらず、かつ、operator delete の介入的な呼び出しによって無効化されていない場合。
- operator delete[] については、ptr の値が、以前の(置換された可能性のある)operator new[](std::size_t)(オーバーロード (2,6,10) の場合)または operator new[](std::size_t, std::align_val_t)(オーバーロード (4,8,12) の場合)によって割り当てられたメモリブロックのアドレスを表しておらず、かつ、operator delete[] の介入的な呼び出しによって無効化されていない場合。
オーバーロード (1-8) は、<new> ヘッダがインクルードされていなくても、各翻訳単位で暗黙的に宣言されます。
delete 式 を参照して、オーバーロードの選択基準を確認してください。
目次 |
[編集] パラメータ
| ptr | - | 解放するメモリブロックへのポインタ、またはヌルポインタ |
| sz | - | 対応する割り当て関数に渡されたサイズ |
| place | - | 対応する配置 new で配置パラメータとして使用されたポインタ |
| tag | - | 例外をスローしない operator new によって使用されたタグと一致するオーバーロードの区別タグ |
| al | - | 割り当てられたオブジェクトまたは配列要素のアラインメント |
| args | - | 対応する配置割り当て関数に一致する任意のパラメータ(std::size_t および std::align_val_t を含む場合があります) |
[編集] 例外
|
宣言で明示的に指定されない限り、すべての非配置解除関数は noexcept(true) です。 |
(C++11以降) |
非配置解除関数が例外をスローして終了した場合、動作は未定義です(noexcept(false) で宣言されている場合でも)。
[編集] グローバル置換
オーバーロード (1-12) は置換可能です。デフォルトバージョンの効果は以下の通りです。
グローバル `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; }
実行結果の例
// 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)
追加のユーザー定義パラメータを持つ operator delete および operator delete[] のオーバーロード(「配置形式」、(15,16))は、通常の通りグローバルスコープで宣言でき、コンストラクタが例外をスローした場合に、配置 new 式の対応する配置形式によって呼び出されます。
標準ライブラリの配置形式の operator delete および operator delete[] (13,14) は置換できず、配置 new 式が `::new` 構文を使用しなかった場合にのみ、対応するシグネチャを持つクラス固有の配置 delete (25,26) を提供することでカスタマイズできます。`void T::operator delete(void*, void*)` または `void T::operator delete[](void*, void*)`。
[編集] クラス固有のオーバーロード
非配置解除関数 (17-24) は、クラスの静的メンバ関数として定義できます。これらの非配置解除関数が提供されている場合、そのクラスのオブジェクト (17,19,21) および配列 (18,20,22) を削除する際に delete 式によって呼び出されます。ただし、delete 式が `::delete` 形式を使用し、クラススコープの検索をバイパスした場合は除きます。これらの関数宣言には `static` キーワードはオプションです。キーワードの使用有無にかかわらず、非配置解除関数は常に静的メンバ関数です。
delete 式は、クラススコープ(配列形式は配列要素クラスのスコープで検索)から対応する非配置解除関数の名前を検索し、メンバが見つからなかった場合は通常通りグローバルスコープに進みます。なお、名前 lookup ルールによれば、クラススコープで宣言された非配置解除関数は、すべてのグローバル非配置解除関数を隠蔽します。
削除されるオブジェクトの静的型が動的型と異なる場合(例えば、基底クラスへのポインタを通じてポリモーフィックなオブジェクトを削除する場合)で、静的型におけるデストラクタが仮想である場合、単一オブジェクト形式の delete は、仮想デストラクタの最終オーバーライダーの定義箇所から非配置解除関数の名前の検索を開始します。実行時にどの非配置解除関数が実行されるかにかかわらず、コンパイルするには、静的に可視な operator delete のバージョンにアクセスできる必要があります。その他の場合、配列を基底クラスへのポインタを通じて削除する場合、または仮想デストラクタのない基底クラスへのポインタを通じて削除する場合、動作は未定義です。
単一引数オーバーロード (17,18) が提供されておらず、2番目のパラメータとして std::size_t を取るサイズ認識オーバーロード (21,22) が提供されている場合、サイズ認識形式が通常の非配置解除のために呼び出され、C++ランタイムは解放されるオブジェクトのサイズを2番目の引数として渡します。両方の形式が定義されている場合、サイズ非認識バージョンが呼び出されます。
#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; }
実行結果の例
custom delete for size 1 custom delete for size 18
追加のユーザー定義パラメータを持つ operator delete および operator delete[] のオーバーロード(「配置形式」、(25,26))もクラスメンバとして定義できます。配置 new 式が失敗した際に、対応する配置 delete 関数を検索するために呼び出される場合、グローバルスコープを調べる前にクラススコープで検索を開始し、配置 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'; } }
出力
custom placement new called, b = 1 custom placement delete called, b = 1 X(): std::runtime_error
クラスレベルの operator delete がテンプレート関数である場合、戻り値の型は void、最初の引数は void* であり、2つ以上のパラメータを持つ必要があります。つまり、配置形式のみがテンプレートになることができます。テンプレートインスタンスは、そのシグネチャにかかわらず、標準的な非配置解除関数ではありません。テンプレート operator delete の特殊化は、テンプレート引数推論によって選択されます。
[編集] 注意
ポリモーフィッククラスに対するクラス固有の T::operator delete の呼び出しは、静的メンバ関数が動的ディスパッチを通じて呼び出される唯一のケースです。
|
以下の関数はスレッドセーフである必要がある
これらの関数に対する、特定のストレージ単位を割り当てるまたは解放する呼び出しは、単一の総順序で発生し、そのような各解放呼び出しは、この順序での次の割り当て(もしあれば)よりhappens-beforeである。 |
(C++11以降) |
| 機能テストマクロ | 値 | 規格 | 機能 |
|---|---|---|---|
__cpp_sized_deallocation |
201309L |
(C++14) | サイズ付き非配置解除 |
__cpp_impl_destroying_delete |
201806L |
(C++20) | Destroying operator delete(コンパイラサポート) |
__cpp_lib_destroying_delete |
201806L |
(C++20) | Destroying operator delete(ライブラリサポート) |
[編集] 欠陥レポート
以下の動作変更を伴う欠陥報告が、以前に公開されたC++標準に遡って適用されました。
| DR | 適用対象 | 公開された動作 | 正しい動作 |
|---|---|---|---|
| CWG 220 | C++98 | ユーザー定義の非配置解除関数は例外をスローすることを許可されていた | 非配置解除関数からの例外スロー 未定義の動作を招く |
| CWG 1438 | C++98 | 無効なポインタ値の使用はすべて未定義の動作であった | 間接参照と非配置解除のみが |
| LWG 206 | C++98 | 置換 (2) は (10) のデフォルト動作に影響を与えなかった | デフォルト動作 それに応じて変更される |
| LWG 298 | C++98 | 置換 (1) は (9) のデフォルト動作に影響を与えなかった | デフォルト動作 それに応じて変更される |
| LWG 404 | C++98 | 置換可能な非配置解除関数の置換 は `inline` と宣言される可能性があった |
禁止、診断は不要 |
| LWG 2458 | C++14 | `(void*, std::size_t, const` `std::nothrow_t&)` を取るオーバーロードが指定されたが、決して呼び出されることはなかった |
無駄なオーバーロードを削除 |
[編集] 関連項目
| [static] (C++23) |
以前 `operator new` から取得したメモリを非配置解除します。 ( std::generator<Ref,V,Allocator>::promise_type の public static メンバ関数) |
| メモリ割り当て関数 (関数) | |
| (C++17で非推奨)(C++20で削除) |
未初期化ストレージを解放します (関数テンプレート) |
| 以前に割り当てられたメモリを解放する (関数) |