名前空間
変種
操作

operator new, operator new[]

提供: cppreference.com
< cpp‎ | memory‎ | new
 
 
 
動的メモリ管理
未初期化記憶域
(C++17)
ガベージコレクションサポート
その他
(C++20)
(C++11)
(C++11)
C のライブラリ
低水準のメモリ管理
 
 
ヘッダ <new> で定義
置き換え可能な確保関数
[[nodiscard]] (C++20およびそれ以降)
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およびそれ以降)
置き換え可能な例外を投げない確保関数
[[nodiscard]] (C++20およびそれ以降)
void* operator new  ( std::size_t count, const std::nothrow_t& tag);
(5)
void* operator new[]( std::size_t count, const std::nothrow_t& tag);
(6)
void* operator new  ( std::size_t count,
                      std::align_val_t al, const std::nothrow_t&);
(7) (C++17およびそれ以降)
void* operator new[]( std::size_t count,
                      std::align_val_t al, const std::nothrow_t&);
(8) (C++17およびそれ以降)
確保しない配置確保関数
[[nodiscard]] (C++20およびそれ以降)
void* operator new  ( std::size_t count, void* ptr );
(9)
void* operator new[]( std::size_t count, void* ptr );
(10)
ユーザ定義の配置確保関数
void* operator new  ( std::size_t count, user-defined-args... );
(11)
void* operator new[]( std::size_t count, user-defined-args... );
(12)
void* operator new  ( std::size_t count,
                      std::align_val_t al, user-defined-args... );
(13) (C++17およびそれ以降)
void* operator new[]( std::size_t count,
                      std::align_val_t al, user-defined-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, user-defined-args... );
(19)
void* T::operator new[]( std::size_t count, user-defined-args... );
(20)
void* T::operator new  ( std::size_t count,
                         std::align_val_t al, user-defined-args... );
(21) (C++17およびそれ以降)
void* T::operator new[]( std::size_t count,
                         std::align_val_t al, user-defined-args... );
(22) (C++17およびそれ以降)

要求されたバイト数を確保します。 これらの確保関数は、初期化される新しいオブジェクトのためのメモリを確保するために、 new 式 によって呼ばれます。 これらは普通の関数呼び出し構文を使用して呼ぶこともできます。

1) 単一のオブジェクトのために要求される記憶域を確保するために、非配列の new 式によって呼ばれます。 標準ライブラリの実装はフリーストアから count バイトを確保します。 失敗した場合、標準ライブラリの実装は std::get_new_handler によって返される関数ポインタを呼び、 new handler が戻らないかヌルポインタになるまで確保の試みを繰り返します。 new handler がヌルポインタの場合は {lc|std::bad_alloc}} を投げます。 この関数はあらゆる基本アライメントのオブジェクトを保持するための適切にアライメントされたポインタを返すことが要求されます。
2) 配列のために要求されるすべての記憶域 (new 式のオーバーヘッドも含むかもしれません) を確保するために、配列形式の new[] 式によって呼ばれます。 標準ライブラリの実装はバージョン (1) を呼びます。
3) __STDCPP_DEFAULT_NEW_ALIGNMENT__ を超えるアライメント要件を持つ単一のオブジェクトのために要求される記憶域を確保するために、非配列の new 式によって呼ばれます。
4) __STDCPP_DEFAULT_NEW_ALIGNMENT__ を超えるアライメント要件を持つオブジェクトの配列のために要求される記憶域を確保するために、配列形式の new[] 式によって呼ばれます。
5) 例外を投げない非配列の new 式によって呼ばれます。 標準ライブラリの実装はバージョン (1) を呼び、失敗時は例外を伝播する代わりにヌルポインタを返します。
6) 例外を投げない配列形式の new[] 式によって呼ばれます。 標準ライブラリの実装はバージョン (2) を呼び、失敗時は例外を伝播する代わりにヌルポインタを返します。
7) オブジェクトのアライメント要件が __STDCPP_DEFAULT_NEW_ALIGNMENT__ を超える場合に、例外を投げない非配列の new 式によって呼ばれます。 標準ライブラリの実装はバージョン (3) を呼び、失敗時は例外を伝播する代わりにヌルポインタを返します。
8) 配列要素のアライメント要件が __STDCPP_DEFAULT_NEW_ALIGNMENT__ を超える場合に、例外を投げない配列形式の new[] 式によって呼ばれます。 標準ライブラリの実装はバージョン (4) を呼び、失敗時は例外を伝播する代わりにヌルポインタを返します。
9) 標準の単一オブジェクトの配置 new 式によって呼ばれます。 標準ライブラリの実装は何も行わず、 ptr を変更せずに返します。
10) 標準の配列形式の配置 new 式によって呼ばれます。 標準ライブラリの実装は何も行わず、 ptr を変更せずに返します。
11) 定義されていれば、一致するシグネチャを持つ単一オブジェクトのカスタムな配置 new 式によって呼ばれます。 クラス固有のバージョン (19) が定義されていれば、それが (11) よりも優先的に呼ばれます。 (11)(19) もユーザによって提供されていなければ、その配置 new 式は ill-formed です。
12) 定義されていれば、一致するシグネチャを持つ配列形式のカスタムな配置 new 式によって呼ばれます。 クラス固有のバージョン (20) が定義されていれば、それが (12) よりも優先的に呼ばれます。 (12)(20) もユーザによって提供されていなければ、その配置 new 式は ill-formed です。
13) 定義されていれば、そのオブジェクトのアライメント要件が __STDCPP_DEFAULT_NEW_ALIGNMENT__ を超える場合に、一致するシグネチャを持つ単一オブジェクトのカスタムな配置 new 式によって呼ばれます。 クラス固有のバージョン ((15) または (17)) が定義されていれば、それが代わりに呼ばれます。 クラス固有のバージョンもグローバルなアライメント対応の配置形式 (このバージョン) も提供されていなければ、代わりにアライメント非対応の配置形式 (11) が探索されます。
14) 定義されていれば、その要素のアライメント要件が __STDCPP_DEFAULT_NEW_ALIGNMENT__ を超える場合に、一致するシグネチャを持つ配列形式のカスタムな配置 new 式によって呼ばれます。 クラス固有のバージョン ((16) または (18)) が定義されていれば、それが代わりに呼ばれます。 クラス固有のバージョンもグローバルなアライメント対応の配置形式 (このバージョン) も提供されていなければ、代わりにアライメント非対応の配置形式 (12) が探索されます。
15) 定義されていれば、型 T のオブジェクトを確保するとき、単一オブジェクトの通常の new 式によって呼ばれます。
16) 定義されていれば、型 T のオブジェクトの配列を確保するとき、配列形式の通常の new[] 式によって呼ばれます。
17) 定義されていれば、型 T のオブジェクトを確保するとき、そのアライメント要件が __STDCPP_DEFAULT_NEW_ALIGNMENT__ を超える場合に、単一オブジェクトの通常の new 式によって呼ばれます。 このオーバーロードが提供されないけれどもアライメント非対応の形式 (15) が提供されている場合は、代わりにアライメント非対応のオーバーロードが呼ばれます。
18) 定義されていれば、型 T のオブジェクトの配列を確保するとき、そのアライメント要件が __STDCPP_DEFAULT_NEW_ALIGNMENT__ を超える場合に、配列形式の通常の new[] 式によって呼ばれます。 このオーバーロードが提供されないけれどもアライメント非対応の形式 (16) が提供されている場合は、代わりにアライメント非対応のオーバーロードが呼ばれます。
19) 定義されていれば、型 T のオブジェクトを確保するとき、一致するシグネチャの単一オブジェクトのカスタムな配置 new 式によって呼ばれます。
20) 定義されていれば、型 T のオブジェクトの配列を確保するとき、一致するシグネチャの配列形式のカスタムな配置 new[] 式によって呼ばれます。
21) 定義されていれば、型 T のオブジェクトを確保するとき、そのアライメント要件が __STDCPP_DEFAULT_NEW_ALIGNMENT__ を超える場合に、単一オブジェクトのカスタムな配置 new 式によって呼ばれます。 このオーバーロードが提供されないけれどもアライメント非対応の形式 (19) が提供されている場合は、代わりにアライメント非対応のオーバーロードが呼ばれます。
22) 定義されていれば、型 T のオブジェクトの配列を確保するとき、そのアライメント要件が __STDCPP_DEFAULT_NEW_ALIGNMENT__ を超える場合に、配列形式のカスタムな配置 new[] 式によって呼ばれます。 このオーバーロードが提供されないけれどもアライメント非対応の形式 (20) が提供されている場合は、代わりにアライメント非対応のオーバーロードが呼ばれます。

目次

[編集] 引数

count - 確保するバイト数
ptr - オブジェクトを初期化するためのメモリ領域を指すポインタ
tag - 例外を投げないオーバーロードを選択するために使用される曖昧性解消タグ
al - 使用するアライメント。 有効なアライメントの値でない場合、動作は未定義です

[編集] 戻り値

少なくとも size バイトの適切にアライメントされたメモリを指す非ヌルなポインタ。

[編集] 例外

1-4,15-18) メモリの確保に失敗した場合、 std::bad_alloc または std::bad_alloc から派生した別の例外 (C++11およびそれ以降)を投げます。
5-10)
(なし) (C++11以前)
noexcept 指定:  
noexcept
  
(C++11およびそれ以降)

[編集] グローバルな置き換え

バージョン (1-4)<new> ヘッダがインクルードされていなくても各翻訳単位で暗黙に定義されます。

バージョン (1-8)置き換え可能です。 プログラム内の任意のソースファイル内の任意の場所で定義された同じシグネチャのユーザ提供の非メンバ関数は、デフォルトのバージョンを置き換えます。 その宣言が可視である必要はありません。

いずれかの置き換え可能な関数に対してプログラム内で2つ以上の置き換えが提供された場合、動作は未定義です。 置き換えが inline 指定子付きで定義された場合、動作は未定義です。 置き換えがグローバル名前空間以外の名前空間で定義された場合、動作は未定義です。 置き換えがグローバルスコープで static な非メンバ関数として定義された場合、動作は未定義です。

例外を投げないバージョン (5-8) の標準ライブラリの実装は、対応する例外を投げるバージョン (1-4) を直接呼びます。 例外を投げる配列バージョン (2,4) の標準ライブラリの実装は、対応する単一オブジェクトバージョン (1,3) を直接呼びます。 そのため、すべての確保を処理するためには、例外を投げる単一オブジェクトの確保関数を置き換えれば十分です。 (C++11およびそれ以降)
#include <cstdio>
#include <cstdlib>
// replacement of a minimal set of functions:
void* operator new(std::size_t sz) {
    std::printf("global op new called, size = %zu\n",sz);
    return std::malloc(sz);
}
void operator delete(void* ptr) noexcept
{
    std::puts("global op delete called");
    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;
}

出力例:

global op new called, size = 4
global op delete called
global op new called, size = 40
global op delete called

ユーザ定義の追加の引数を持つ operator new および operator new[] のオーバーロード (11-14) (「配置形式」) は通常通りグローバルスコープで宣言でき、一致する配置形式の new 式 によって呼ばれます。

標準ライブラリの確保しない配置形式の operator new (9-10) は、置き換えることはできず、配置 new 式が ::new 構文を使用しない場合に、一致するシグネチャ (void* T::operator new(size_t, void*) または void* T::operator new[](size_t, void*)) を持つクラス固有の配置 new (19,20) を提供することによってのみ、カスタマイズできます。

配置形式 void* operator new(std::size_t, std::size_t) は、一致するシグネチャの解放関数 void operator delete(void*, std::size_t) が通常の (非配置) 解放関数であるため、使用できません。

(C++14およびそれ以降)

[編集] クラス固有のオーバーロード

単一オブジェクトと配列の確保関数はどちらも、クラスのパブリックな static メンバとして定義できます (バージョン {v|15-18}})。 定義されていれば、そのクラスの単一オブジェクトまたは配列のためのメモリを確保するために、 new 式によってこれらの確保関数が呼ばれます。 ただしその new 式がクラススコープの探索をバイパスする ::new の形式を使用している場合を除きます。 キーワード static はこれらの関数に対しては任意であり、使用されようがされなかろうが、確保関数は static メンバ関数です。

new 式は適切な確保関数の名前をまずクラススコープから、その後グローバルスコープから探します。 名前探索のルールにより、クラススコープで宣言されたいずれかの確保関数は、そのクラスのオブジェクトの確保を試みる new 式に対して、すべてのグローバル関数を隠蔽することに注意してください。

__STDCPP_DEFAULT_NEW_ALIGNMENT__ を超えるアライメントを持つオブジェクトまたはオブジェクトの配列を確保するとき、オーバーロード解決は2回、まずアライメント対応の関数シグネチャについて、その後アライメント非対応の関数シグネチャに対してついて行われます。 これは、拡張アライメントを持つクラスがアライメント非対応なクラス固有の確保関数を持つ場合、それが呼ばれる関数であり、グローバルなアライメント対応確保関数ではないことを意味します。 これは意図的なものです。 そのクラスのメンバはそのクラスの処理方法を最も良く知っているはずです。

(C++17およびそれ以降)
#include <iostream>
// class-specific allocation functions
struct X {
    static void* operator new(std::size_t sz)
    {
        std::cout << "custom new for size " << sz << '\n';
        return ::operator new(sz);
    }
    static void* operator new[](std::size_t sz)
    {
        std::cout << "custom new for size " << sz << '\n';
        return ::operator new(sz);
    }
};
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およびそれ以降)
#include <stdexcept>
#include <iostream>
struct X {
    X() { throw 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 {
     X* p1 = new (true) X;
   } catch(const std::exception&) { }
}

出力:

custom placement new called, b = 1
custom placement delete called, b = 1

クラスレベルの operator new がテンプレート関数の場合、その戻り値型は void*、第1引数は std::size_t でなければならず、2つ以上の引数を取らなければなりません。 別の言い方をすると、配置形式のみがテンプレート化できます。

[編集] ノート

確保しない配置 new (9,10) を置き換えることはできませんが、上記の通り、クラススコープで同じシグネチャの関数を定義することはできます。 また、第2引数として void でないポインタを取る配置 new っぽいグローバルなオーバーロードも可能であるため、真の配置 new が呼ばれることを保証したいコード (std::allocator::construct など) は、 ::new を使用しなければならず、また、ポインタを void* にキャストしなければなりません。

以下の関数はスレッドセーフであることが要求されます。

記憶域の特定の単位を確保または解放するこれらの関数の呼び出しは単一の全順序で発生し、そのような解放の呼び出しそれぞれはこの順序における次の確保 (もしあれば) に対して先行発生します。

(C++11およびそれ以降)

operator new のライブラリバージョンが std::malloc または std::aligned_alloc (C++17およびそれ以降) の呼び出しを行うかどうかは未規定です。

[編集]

operator new のカスタム配置形式は任意の目的に使用できます。 例えば確保した配列を塗りつぶすとか。

#include <iostream>
#include <algorithm>
 
void* operator new[](std::size_t sz, char c)
{
    void* p = operator new[](sz);
    std::fill_n(reinterpret_cast<char*>(p), sz, c);
    return p;
}
 
int main()
{
    char* p = new('*') char[6];
    p[5] = '\0';
    std::cout << p << '\n';
    delete[] p;
}

出力:

*****

[編集] 関連項目

解放関数
(関数) [edit]
現在の new ハンドラを取得します
(関数) [edit]
new ハンドラを登録します
(関数) [edit]
(deprecated in C++17)
未初期化記憶域を取得します
(関数テンプレート) [edit]
メモリを確保します
(関数)
アラインされたメモリを確保します
(関数)

[編集] 参考文献

  • C++11 standard (ISO/IEC 14882:2011):
  • 18.6 Dynamic memory management [support.dynamic]