operator new, operator new[]
| ヘッダ <new> で定義 |
||
| 置換可能な確保関数 |
||
void* operator new ( std::size_t count ); |
(1) | |
void* operator new[]( std::size_t count ); |
(2) | |
void* operator new ( std::size_t count, std::align_val_t al ); |
(3) | (C++17以降) |
void* operator new[]( std::size_t count, std::align_val_t al ); |
(4) | (C++17以降) |
| 例外を投げない置換可能な確保関数 |
||
void* operator new ( std::size_t count, const std::nothrow_t& tag ); |
(5) | (C++11 以降 noexcept) |
void* operator new[]( std::size_t count, const std::nothrow_t& tag ); |
(6) | (C++11 以降 noexcept) |
void* operator new ( std::size_t count, std::align_val_t al, const std::nothrow_t& tag ) noexcept; |
(7) | (C++17以降) |
void* operator new[]( std::size_t count, std::align_val_t al, const std::nothrow_t& tag ) noexcept; |
(8) | (C++17以降) |
| 配置しない配置確保関数 |
||
void* operator new ( std::size_t count, void* ptr ); |
(9) | (C++11 以降 noexcept) (C++26 以降 constexpr) |
void* operator new[]( std::size_t count, void* ptr ); |
(10) | (C++11 以降 noexcept) (C++26 以降 constexpr) |
| ユーザー定義配置確保関数 |
||
void* operator new ( std::size_t count, /* args... */ ); |
(11) | |
void* operator new[]( std::size_t count, /* args... */ ); |
(12) | |
void* operator new ( std::size_t count, std::align_val_t al, /* args... */ ); |
(13) | (C++17以降) |
void* operator new[]( std::size_t count, std::align_val_t al, /* args... */ ); |
(14) | (C++17以降) |
| クラス固有の確保関数 |
||
void* T::operator new ( std::size_t count ); |
(15) | |
void* T::operator new[]( std::size_t count ); |
(16) | |
void* T::operator new ( std::size_t count, std::align_val_t al ); |
(17) | (C++17以降) |
void* T::operator new[]( std::size_t count, std::align_val_t al ); |
(18) | (C++17以降) |
| クラス固有の配置確保関数 |
||
void* T::operator new ( std::size_t count, /* args... */ ); |
(19) | |
void* T::operator new[]( std::size_t count, /* args... */ ); |
(20) | |
void* T::operator new ( std::size_t count, std::align_val_t al, /* args... */ ); |
(21) | (C++17以降) |
void* T::operator new[]( std::size_t count, std::align_val_t al, /* args... */ ); |
(22) | (C++17以降) |
指定されたバイト数を確保しようとします。確保要求は(要求バイト数がゼロの場合でも)失敗する可能性があります。これらの確保関数は、新しいオブジェクトが初期化されるメモリを確保するために、new 式によって呼び出されます。通常の関数呼び出し構文を使用して呼び出されることもあります。
オーバーロード (1-4) は、<new> ヘッダーがインクルードされていなくても、各翻訳単位で暗黙的に宣言されます。
new 式のオーバーロード選択基準については、new 式を参照してください。
目次 |
[編集] パラメータ
| count | - | 割り当てるバイト数 |
| ptr | - | オブジェクトを初期化するメモリ領域へのポインタ |
| タグ | - | 例外を投げないオーバーロードを選択するための区別タグ |
| al | - | 使用するアライメント。無効な値は未定義の動作につながります。 |
[編集] 戻り値
[編集] 例外
[編集] グローバル置換
オーバーロード (1-8) は置換可能です。デフォルトバージョンの効果は次のとおりです。
- 試行が成功した場合、確保されたストレージへのポインタを返します。
- それ以外の場合、現在 newハンドラがインストールされていない場合は、std::bad_alloc をスローします。
- それ以外の場合、現在インストールされている newハンドラを呼び出します。
- newハンドラが戻った場合、別の確保試行を開始します。
- それ以外の場合、現在の呼び出しを終了します。
- 呼び出しが正常に戻った場合、その呼び出しの結果を返します。
- それ以外の場合、ヌルポインタを返します。
|
フリースタンディング実装では、(1-8) の置換可能なグローバル確保関数のデフォルトバージョンが上記の要件を満たすかどうかは実装定義です。フリースタンディング実装では、これらのデフォルトバージョンのいずれかがホステッド実装の要件を満たす場合、すべてが満たすべきであることが推奨されます。 |
(C++26以降) |
グローバル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 new および operator new[] のオーバーロード(「配置形式」、バージョン (11-14))は、通常どおりグローバルスコープで宣言でき、new 式の対応する配置形式によって呼び出されます。
標準ライブラリの配置しない配置形式の operator new (9,10) は置換できず、対応するシグネチャを持つクラス固有の配置 new を提供することによってのみカスタマイズできます(バージョン (19,20)):void* T::operator new(std::size_t, void*) または void* T::operator new[](std::size_t, void*)。
|
配置形式 void* operator new(std::size_t, std::size_t) は許可されていません。なぜなら、対応する解放関数のシグネチャ void operator delete(void*, std::size_t) が通常の(配置ではない)解放関数であるためです。 |
(C++14以降) |
[編集] クラス固有のオーバーロード
単一オブジェクトおよび配列の確保関数は、クラスの public static メンバー関数として定義できます(バージョン (15-18))。定義された場合、これらの確保関数は new 式によって、このクラスの単一オブジェクトおよび配列のメモリを確保するために呼び出されます。ただし、new 式が ::new 形式を使用し、クラススコープの検索をバイパスした場合は除きます。キーワード static はこれらの関数ではオプションです。使用されていてもされていなくても、確保関数は static メンバー関数です。
new 式は、まずクラススコープで、次にグローバルスコープで、適切な確保関数の名前を検索します。なお、名前 lookup ルールに従って、クラススコープで宣言された確保関数は、このクラスのオブジェクトを確保しようとする new 式に対して、すべてのグローバル確保関数を隠蔽します。
|
アライメントが __STDCPP_DEFAULT_NEW_ALIGNMENT__ を超えるオブジェクトとオブジェクト配列を確保する場合、オーバーロード解決は 2 回実行されます。まず、アライメントを認識する関数シグネチャに対して、次にアライメントを認識しない関数シグネチャに対して実行されます。これは意図的です。クラスメンバーはそのクラスの扱い方を最もよく知っていると期待されるためです。 |
(C++17以降) |
|
__STDCPP_DEFAULT_NEW_ALIGNMENT__ を超えないアライメントのオブジェクトとオブジェクト配列を確保する場合、オーバーロード解決は 2 回実行されます。まず、アライメントを認識しない関数シグネチャに対して、次にアライメントを認識する関数シグネチャに対して実行されます。 |
(C++20以降) |
#include <cstddef> #include <iostream> // class-specific allocation functions struct X { static void* operator new(std::size_t count) { std::cout << "custom new for size " << count << '\n'; return ::operator new(count); } static void* operator new[](std::size_t count) { std::cout << "custom new[] for size " << count << '\n'; return ::operator new[](count); } }; int main() { X* p1 = new X; delete p1; X* p2 = new X[10]; delete[] p2; }
実行結果の例
custom new for size 1 custom new[] for size 10
追加のユーザー定義パラメータを持つ operator new および operator new[] のオーバーロード(「配置形式」)も、クラスメンバーとして定義できます(バージョン (19-22))。対応する確保関数を呼び出すために、対応するシグネチャを持つ配置 new 式が検索されるとき、グローバルスコープを調べる前にクラススコープから開始します。クラス固有の配置 new が提供されている場合、それが呼び出されます。
|
__STDCPP_DEFAULT_NEW_ALIGNMENT__ を超えるアライメントのオブジェクトとオブジェクト配列を確保する場合、配置形式のオーバーロード解決は、通常の形式と同様に 2 回実行されます。まず、アライメントを認識する関数シグネチャに対して、次にアライメントを認識しない関数シグネチャに対して実行されます。 |
(C++17以降) |
|
__STDCPP_DEFAULT_NEW_ALIGNMENT__ を超えないアライメントのオブジェクトとオブジェクト配列を確保する場合、配置形式のオーバーロード解決は、通常の形式と同様に 2 回実行されます。まず、アライメントを認識しない関数シグネチャに対して、次にアライメントを認識する関数シグネチャに対して実行されます。 |
(C++20以降) |
#include <cstddef> #include <iostream> #include <stdexcept> struct X { X() { throw std::runtime_error(""); } // custom placement new static void* operator new(std::size_t count, bool b) { std::cout << "custom placement new called, b = " << b << '\n'; return ::operator new(count); } // 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&) {} }
出力
custom placement new called, b = 1 custom placement delete called, b = 1
クラスレベルの operator new がテンプレート関数である場合、返り値の型は void*、最初の引数は std::size_t でなければならず、2 つ以上のパラメータを持つ必要があります。つまり、配置形式のみがテンプレートである可能性があります。
[編集] 注記
配置しない配置 new (9,10) は置換できませんが、同じシグネチャを持つ関数はクラススコープで定義できます(上記参照)。さらに、配置 new のように見えるが 2 番目の引数として非 void ポインタ型を取るグローバルオーバーロードは許可されています。したがって、真の配置 new が呼び出されることを保証したいコード(例:std::allocator::construct)は、::new を使用し、ポインタを void* にキャストする必要があります。
解放関数の動作がデフォルトの制約を満たさない場合、動作は未定義です。
|
以下の関数はスレッドセーフである必要がある
これらの関数に対する、特定のストレージ単位を割り当てるまたは解放する呼び出しは、単一の総順序で発生し、そのような各解放呼び出しは、この順序での次の割り当て(もしあれば)よりhappens-beforeである。 |
(C++11以降) |
ライブラリバージョンの operator new が std::malloc または std::aligned_alloc(C++17以降) を呼び出すかどうかは未指定です。
大きなファイルをロードするために、OS固有の関数(POSIX の mmap や Windows の CreateFileMapping(A/W) と MapViewOfFile)によるファイルマッピングは、ファイル読み込み用のバッファを確保するよりも推奨されます。
| 機能テストマクロ | 値 | 規格 | 機能 |
|---|---|---|---|
__cpp_lib_freestanding_operator_new |
202306L |
(C++26) | 置換可能な operator new のフリースタンディングサポート[1] |
0 |
(C++26) | フリースタンディングサポートなし | |
__cpp_lib_constexpr_new |
202406L |
(C++26) | constexpr 配置 new および new[] |
- ↑ 正式には、このマクロは、置換可能なグローバル確保関数のすべてのデフォルトバージョンがホステッド実装の要件を満たす場合、202306L に展開されます。
[編集] 欠陥報告
以下の動作変更を伴う欠陥報告が、以前に公開されたC++標準に遡って適用されました。
| DR | 適用対象 | 公開された動作 | 正しい動作 |
|---|---|---|---|
| CWG 521 | C++98 | std::bad_alloc から派生した任意のクラスをスローできた。std::bad_alloc の基底が曖昧またはアクセス不能である場合でも。 |
スローされる例外は一致すべきである。 ハンドラは std::bad_alloc 型である。 |
| LWG 9 | C++98 | ゼロバイトの確保のための複数の呼び出し 同じポインタを生成する可能性がある。 |
以前に生成されたすべてのポインタが 解放関数に渡された場合のみ許可される。 解放関数に渡されている場合。 |
| LWG 206 | C++98 | 置換可能な確保関数の置換は、対応する 置換可能な例外を投げない確保関数のデフォルト動作に影響しなかった。 デフォルトの動作は |
それに応じて変更される。 変更される。 |
| LWG 404 | C++98 | 置換可能な確保関数の置換は inline として宣言できる 宣言できる。 |
診断は不要。 |
[編集] 参照
- C++23標準 (ISO/IEC 14882:2024)
- 17.7 動的メモリ管理 [support.dynamic]
- C++20 standard (ISO/IEC 14882:2020)
- 17.6 動的メモリ管理 [support.dynamic]
- C++17 standard (ISO/IEC 14882:2017)
- 21.6 動的メモリ管理 [support.dynamic]
- C++14 standard (ISO/IEC 14882:2014)
- 18.6 動的メモリ管理 [support.dynamic]
- C++11 standard (ISO/IEC 14882:2011)
- 18.6 動的メモリ管理 [support.dynamic]
- C++03 標準 (ISO/IEC 14882:2003)
- 18.4 動的メモリ管理 [lib.support.dynamic]
- C++98 標準 (ISO/IEC 14882:1998)
- 18.4 動的メモリ管理 [lib.support.dynamic]
[編集] 関連項目
| [static] (C++23) |
Allocator を使用してメモリを確保する( std::generator<Ref,V,Allocator>::promise_type の public static メンバー関数) |
| メモリ解放関数 (関数) | |
| (C++11) |
現在のnewハンドラを取得する (関数) |
| newハンドラを登録する (関数) | |
| (C++17で非推奨)(C++20で削除) |
未初期化ストレージを取得します (関数テンプレート) |
| メモリを割り当てる (関数) | |
| (C++17) |
アラインされたメモリを割り当てる (関数) |