Namespaces
Variants

演算子 new、演算子 new[]

ja.cppreference.net より
 
 
ユーティリティライブラリ
言語サポート
型サポート (基本型、RTTI)
ライブラリ機能テストマクロ (C++20)
プログラムユーティリティ
可変長引数関数
コルーチンサポート (C++20)
契約サポート (C++26)
三方比較
(C++20)
(C++20)(C++20)(C++20)    
(C++20)(C++20)(C++20)

汎用ユーティリティ
関係演算子 (C++20で非推奨)
整数比較関数
(C++20)(C++20)(C++20)    
(C++20)
Swap と 型操作
(C++14)
(C++11)
(C++11)
(C++11)
(C++17)
共通のボキャブラリ型
(C++11)
(C++17)
(C++17)
(C++17)
(C++11)
(C++17)
(C++23)



 
メモリ管理ライブラリ
アロケータ
メモリリソース
未初期化ストレージ (C++20まで*)
ガベージコレクタサポート (C++23まで)
 
 
ヘッダ <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 式によって呼び出され、新しいオブジェクトが初期化されるメモリを確保します。通常の関数呼び出し構文を使用して呼び出すこともできます。

1-8) 置換可能な確保関数。標準ライブラリはこれらの関数のデフォルト実装を提供します。デフォルト実装の効果については、以下を参照してください。
9,10) 標準の 配置 new式によって呼び出されます。何も実行せず、ptr を変更せずに返します。
この関数が配置 new を通じて呼び出され、ptr がヌルポインタである場合、動作は未定義です。
11-22) new 式によって呼び出されるユーザー定義の確保関数。

オーバーロード (1-4) は、<new> ヘッダがインクルードされていなくても、各翻訳単位で暗黙的に宣言されます。

オーバーロード選択の基準については、new 式 を参照してください。

パラメータ

count - 割り当てるバイト数
ptr - オブジェクトを初期化するメモリ領域へのポインタ
tag - 非スローオーバーロードを選択するための区別タグ
al - 使用するアライメント、無効な値は未定義動作を引き起こす

戻り値

1-4) メモリ確保が成功した場合、非ヌルポインタ p0 を返す。このポインタは少なくとも size バイトの適切にアラインされたメモリ領域を指し、かつ以前に返された値 p1 とは異なる(ただし、その値 p1 がその後 解放関数 に渡された場合は除く)。メモリ確保が失敗した場合は戻らない(例外がスローされる。詳細は後述)。
5-8) 以下は ( 1-4 ) と同じですが、メモリ確保に失敗した場合はヌルポインタを返します。
9,10) ptr
11-22) 割り当て失敗時に戻らない場合は ( 1-4 ) と同じ、それ以外の場合は ( 5-8 ) と同じ。

例外

1-4) メモリの割り当てに失敗した場合、 std::bad_alloc 型のハンドラに一致する型の例外をスローします。
11-22) 割り当て失敗時に戻らない場合は ( 1-4 ) と同じ、それ以外の場合は ( 5-8 ) と同じ。

グローバル置換

多重定義 (1-8) は置換可能です。デフォルトのバージョンの効果は以下の通りです:

1) 要求されたストレージを割り当てようと試みます。その試みが std::malloc または std::aligned_alloc の呼び出しを伴うかどうかは未規定です。
  • 試みが成功した場合、割り当てられたストレージへのポインタを返します。ストレージは基本アライメントに整列されます(C++17未満)ストレージは __STDCPP_DEFAULT_NEW_ALIGNMENT__ に整列されます(C++17以上)
  • 。それ以外の場合、現在新しいハンドラが設定されていなければ、std::bad_alloc を送出します。
  • それ以外の場合、現在設定されている新しいハンドラを呼び出します。
    • 新しいハンドラが戻った場合、別の割り当て試行を開始します。
    • それ以外の場合、現在の呼び出しを終了します。
2) operator new(count) を返します。
3) (1) と同じですが、返されるストレージが al に整列される点が異なります。
4) operator new(count, al) を返します。
5-8) それぞれ (1-4) を、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*)。

配置形式 void* operator new(std::size_t, std::size_t) は許可されません。なぜなら、解放関数の一致するシグネチャ void operator delete(void*, std::size_t) は通常の(配置ではない)解放関数だからです。

(C++14以上)

クラス固有のオーバーロード

単一オブジェクトおよび配列の確保関数は、どちらもクラスのパブリックスタティックメンバ関数として定義できます(バージョン (15-18))。これらが定義されている場合、これらの確保関数は、new 式によって呼び出され、このクラスの単一オブジェクトおよび配列のメモリを確保します。ただし、new 式がクラススコープでの名前探索をバイパスする形式 ::new を使用している場合は除きます。これらの関数ではキーワード static はオプションです。使用の有無にかかわらず、確保関数は静的メンバ関数です。

new 式は、最初にクラススコープ内で、次にグローバルスコープ内で適切な確保関数の名前を探します。なお、名前探索ルール に従い、クラススコープで宣言された確保関数は、このクラスのオブジェクトを確保しようとする new 式に対して、すべてのグローバル確保関数を隠蔽することに注意してください。

__STDCPP_DEFAULT_NEW_ALIGNMENT__ を超えるアライメントを持つオブジェクトおよびオブジェクト配列を確保する場合、オーバーロード解決は2回実行されます。最初にアライメントを考慮する関数シグネチャ、その後アライメントを考慮しない関数シグネチャに対して行われます。これは、new拡張アライメント を持つクラスにアライメントを考慮しないクラス固有の確保関数がある場合、グローバルのアライメントを考慮する確保関数ではなく、その関数が呼び出されることを意味します。これは意図的です。クラスメンバは、そのクラスの扱い方を最もよく知っていると期待されます。

(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 のように見えるが第二引数として非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 [ ]
  1. ↑ 形式的には、このマクロは 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メンバー関数)
解放関数
(関数)
現在のnewハンドラを取得する
(関数)
新しいハンドラを登録する
(関数)
(C++17で非推奨) (C++20で削除)
初期化されていないストレージを取得する
(関数テンプレート)
メモリを割り当てる
(関数)
アライメントされたメモリを割り当てる
(関数)