名前空間
変種
操作

operator new, operator new[]

From cppreference.com
< cpp‎ | memory‎ | new
 
 
ユーティリティライブラリ
言語サポート
型のサポート (基本型、RTTI)
ライブラリ機能検査マクロ (C++20)
プログラムユーティリティ
可変引数関数
コルーチンサポート (C++20)
契約サポート (C++26)
三方比較
(C++20)
(C++20)(C++20)(C++20)  
(C++20)(C++20)(C++20)

汎用ユーティリティ
関係演算子 (C++20で非推奨)
 
メモリ管理ライブラリ
(説明用*)
未初期化メモリのアルゴリズム
(C++17)
(C++17)
(C++17)
制約付き未初期化
メモリアルゴリズム
Cライブラリ

アロケータ
メモリリソース
ガベージコレクションのサポート
(C++11)(C++23まで)
(C++11)(C++23まで)
(C++11)(C++23まで)
(C++11)(C++23まで)
(C++11)(C++23まで)
(C++11)(C++23まで)
未初期化ストレージ
(C++20まで*)
(C++20まで*)
明示的な生存期間管理
 
 
ヘッダ <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-8) 置換可能な確保関数。標準ライブラリはこれらの関数のデフォルト実装を提供します。デフォルト実装の効果については、下記を参照してください。
9,10) 標準の配置 new 式によって呼び出されます。何もせず、ptr を変更せずに返します。
この関数が配置 new を介して呼び出され、ptr がヌルポインタである場合、動作は未定義です。
11-22) new 式によって呼び出されるユーザー定義確保関数。

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

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

目次

[編集] パラメータ

count - 割り当てるバイト数
ptr - オブジェクトを初期化するメモリ領域へのポインタ
タグ - 例外を投げないオーバーロードを選択するための区別タグ
al - 使用するアライメント。無効な値は未定義の動作につながります。

[編集] 戻り値

1-4) 確保が成功した場合、サイズ size 以上で適切にアライメントされたメモリを指す非ヌルポインタ p0 を返します。このポインタは、以前に返された値 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 の呼び出しを含むかどうかは未指定です。
  • 試行が成功した場合、確保されたストレージへのポインタを返します。
  • それ以外の場合、現在 newハンドラがインストールされていない場合は、std::bad_alloc をスローします。
  • それ以外の場合、現在インストールされている newハンドラを呼び出します。
    • newハンドラが戻った場合、別の確保試行を開始します。
    • それ以外の場合、現在の呼び出しを終了します。
2) operator new(count) を返します。
3) (1) と同じです。
4) operator new(count, al) を返します。
5-8) それぞれ (1-4) を、tag 以外の同じ引数で呼び出します。
  • 呼び出しが正常に戻った場合、その呼び出しの結果を返します。
  • それ以外の場合、ヌルポインタを返します。

フリースタンディング実装では、(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 newstd::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[]
  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 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 メンバー関数) [編集]
メモリ解放関数
(関数) [編集]
現在のnewハンドラを取得する
(関数) [編集]
newハンドラを登録する
(関数) [編集]
(C++17で非推奨)(C++20で削除)
未初期化ストレージを取得します
(関数テンプレート) [編集]
メモリを割り当てる
(関数) [編集]
アラインされたメモリを割り当てる
(関数) [編集]
English 日本語 中文(简体) 中文(繁體)