演算子 new、演算子 new[]
| ヘッダ <new>
|
||
| で定義 |
||
void* operator new ( std::size_t count );
|
置換可能な確保関数 | |
void* operator new[]( std::size_t count );
|
(1) | |
void* operator new ( std::size_t count, std::align_val_t al );
|
(2) | (C++17 以降) |
void* operator new[]( std::size_t count, std::align_val_t al );
|
(3) | (C++17 以降) |
| 置換可能な例外を投げない確保関数 |
||
void* operator new ( std::size_t count, const std::nothrow_t& tag );
|
(4) | (C++11 以降 noexcept) |
void* operator new[]( std::size_t count, const std::nothrow_t& tag );
|
(5) | (C++11 以降 noexcept) |
void* operator new ( std::size_t count, std::align_val_t al,
const std::nothrow_t& tag ) noexcept;
|
(6) | (C++17 以降) |
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, void* ptr );
|
(8) | (C++11 以降 noexcept) (C++26 以降 constexpr) |
void* operator new[]( std::size_t count, void* ptr );
|
(9) | (C++11 以降 noexcept) (C++26 以降 constexpr) |
| ユーザー定義配置確保関数 |
||
void* operator new ( std::size_t count, /* args... */ );
|
(10) | |
void* operator new[]( std::size_t count, /* args... */ );
|
(11) | |
void* operator new ( std::size_t count,
std::align_val_t al, /* args... */ );
|
(12) | (C++17 以降) |
void* operator new[]( std::size_t count,
std::align_val_t al, /* args... */ );
|
(13) | (C++17 以降) |
| クラス固有の確保関数 |
||
void* T::operator new ( std::size_t count );
|
(14) | |
void* T::operator new[]( std::size_t count );
|
(15) | |
void* T::operator new ( std::size_t count, std::align_val_t al );
|
(16) | (C++17 以降) |
void* T::operator new[]( std::size_t count, std::align_val_t al );
|
(17) | (C++17 以降) |
| クラス固有の配置確保関数 |
||
void* T::operator new ( std::size_t count, /* args... */ );
|
(18) | |
void* T::operator new[]( std::size_t count, /* args... */ );
|
(19) | |
void* T::operator new ( std::size_t count,
std::align_val_t al, /* args... */ );
|
(20) | (C++17 以降) |
void* T::operator new[]( std::size_t count,
std::align_val_t al, /* args... */ );
|
(21) | (C++17 以降) |
要求されたバイト数の確保を試みます。確保要求は(要求されたバイト数がゼロであっても)失敗する可能性があります。これらの確保関数は new 式によって呼び出され、新しいオブジェクトが初期化されるメモリを確保します。通常の関数呼び出し構文を使用して呼び出すこともできます。
new を通じて呼び出され、ptr がヌルポインタである場合、動作は未定義です。new 式によって呼び出されるユーザー定義の確保関数。オーバーロード (1-4) は、<new> ヘッダがインクルードされていなくても、各翻訳単位で暗黙的に宣言されます。
オーバーロード選択の基準については、new 式 を参照してください。
パラメータ
| count | - | 割り当てるバイト数 |
| ptr | - | オブジェクトを初期化するメモリ領域へのポインタ |
| tag | - | 非スローオーバーロードを選択するための区別タグ |
| al | - | 使用するアライメント、無効な値は未定義動作を引き起こす |
戻り値
例外
グローバル置換
多重定義 (1-8) は置換可能です。デフォルトのバージョンの効果は以下の通りです:
- 試みが成功した場合、割り当てられたストレージへのポインタを返します。ストレージは基本アライメントに整列されます(C++17未満)ストレージは
__STDCPP_DEFAULT_NEW_ALIGNMENT__に整列されます(C++17以上) - 。それ以外の場合、現在新しいハンドラが設定されていなければ、std::bad_alloc を送出します。
- それ以外の場合、現在設定されている新しいハンドラを呼び出します。
- 新しいハンドラが戻った場合、別の割り当て試行を開始します。
- それ以外の場合、現在の呼び出しを終了します。
operator new(count) を返します。al に整列される点が異なります。operator new(count, al) を返します。tag を除いて同じ引数で呼び出します。
- 呼び出しが正常に戻った場合、その呼び出しの結果を返します。
- それ以外の場合、ヌルポインタを返します。
|
フリースタンディング実装では、(1-8) のデフォルトバージョンが上記の要求される動作を満たすかどうかは実装定義です。フリースタンディング実装では、これらのデフォルトバージョンのいずれかがホスト実装の要件を満たす場合、それらすべてが満たすことが推奨されます。 |
(C++26以上) |
グローバル operators 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 式が ::new 構文を使用しない場合にのみ、一致するシグネチャを持つクラス固有の配置 new (19,20) を提供することでカスタマイズできます: void* T::operator new(std::size_t, void*) または void* T::operator new[](std::size_t, void*)。
|
配置形式 |
(C++14以上) |
クラス固有のオーバーロード
単一オブジェクトおよび配列の確保関数は、どちらもクラスのパブリックスタティックメンバ関数として定義できます(バージョン (15-18))。これらが定義されている場合、これらの確保関数は、new 式によって呼び出され、このクラスの単一オブジェクトおよび配列のメモリを確保します。ただし、new 式がクラススコープでの名前探索をバイパスする形式 ::new を使用している場合は除きます。これらの関数ではキーワード static はオプションです。使用の有無にかかわらず、確保関数は静的メンバ関数です。
new 式は、最初にクラススコープ内で、次にグローバルスコープ内で適切な確保関数の名前を探します。なお、名前探索ルール に従い、クラススコープで宣言された確保関数は、このクラスのオブジェクトを確保しようとする new 式に対して、すべてのグローバル確保関数を隠蔽することに注意してください。
|
|
(C++17 以降) |
|
|
(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 が提供されている場合、それが呼び出されます。
|
|
(C++17 以降) |
|
|
(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 のように見えるが第二引数として非voidポインタ型を取るグローバルなオーバーロードが許可されているため、真の配置 new が呼び出されることを保証したいコード(例: std::allocator::construct )は、 :: new を使用し、さらにポインタを void * にキャストする必要があります。
解放関数の動作がデフォルトの制約を満たさない場合、その動作は未定義です。
|
以下の関数はスレッドセーフであることが要求されます:
特定の記憶単位を割り当てまたは解放するこれらの関数の呼び出しは、単一の全順序で発生し、それぞれの解放呼び出しは 先行発生 します(この順序における次の割り当て(もしあれば)に対して)。 |
(C++11以降) |
ライブラリバージョンの
operator new
が
std::malloc
または
std::aligned_alloc
(C++17以降)
を呼び出すかどうかは未規定です。
大容量ファイルの読み込みには、ファイル読み込み用のバッファを割り当てるよりも、OS固有の機能によるファイルマッピング、例えば
mmap
on POSIX または
CreateFileMapping
(
A
/
W
) と
MapViewOfFile
on Windows を使用する方が望ましいです。
| 機能テスト マクロ | 値 | 標準 | 機能 |
|---|---|---|---|
__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標準 (ISO/IEC 14882:2020):
-
- 17.6 動的メモリ管理 [support.dynamic]
- C++17 標準 (ISO/IEC 14882:2017):
-
- 21.6 動的メモリ管理 [support.dynamic]
- C++14 標準 (ISO/IEC 14882:2014):
-
- 18.6 動的メモリ管理 [support.dynamic]
- C++11標準 (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ハンドラを取得する
(関数) |
|
新しいハンドラを登録する
(関数) |
|
|
(C++17で非推奨)
(C++20で削除)
|
初期化されていないストレージを取得する
(関数テンプレート) |
|
メモリを割り当てる
(関数) |
|
|
(C++17)
|
アライメントされたメモリを割り当てる
(関数) |