名前空間
変種
操作

new

From cppreference.com
< cpp‎ | language
 
 
C++言語
全般
フロー制御
条件実行文
if
繰り返し文 (ループ)
for
範囲for (C++11)
ジャンプ文
関数
関数宣言
ラムダ式
inline指定子
動的例外仕様 (C++17まで*)
noexcept指定子 (C++11)
例外
名前空間
指定子
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
記憶域期間指定子
初期化
代替表現
リテラル
ブーリアン - 整数 - 浮動小数点数
文字 - 文字列 - nullptr (C++11)
ユーザー定義 (C++11)
ユーティリティ
属性 (C++11)
typedef宣言
型エイリアス宣言 (C++11)
キャスト
メモリ確保
new
クラス
クラス固有の関数プロパティ
explicit (C++11)
static

特殊メンバ関数
テンプレート
その他
 
 

動的な記憶域期間を持つオブジェクト、すなわち、その生存期間が必ずしも作成されたスコープに限定されないオブジェクトを作成し、初期化します。

目次

[編集] 構文

::(optional) new ( ) new-initializer (optional) (1)
::(optional) new new-initializer (optional) (2)
::(optional) new (placement-args ) ( ) new-initializer (optional) (3)
::(optional) new (placement-args ) new-initializer (optional) (4)
1,2) typeで示される型のオブジェクトを作成しようとします。これは配列型である場合がありプレースホルダ型指定子を含む場合があり(C++11以降)、また、クラステンプレート引数推論によって引数が推論されるクラステンプレート名を含む場合があります(C++17以降)
3,4) (1,2) と同じですが、メモリ確保関数に追加の引数を提供します。配置 new を参照してください。

[編集] 説明

type - 対象の型名
new-initializer - 丸括弧で囲まれた式リスト または 波括弧で囲まれた初期化子リスト(C++11以降)
placement-args - 追加の配置引数


new 式は、メモリを確保し、その後、確保されたメモリ内に単一の未命名オブジェクト、またはオブジェクトの配列を構築および初期化しようとします。new 式は、構築されたオブジェクトへの prvalue ポインタ、またはオブジェクトの配列が構築された場合は配列の最初の要素へのポインタを返します。

構文 (1) または (3) は、type に丸括弧が含まれる場合に必要です。

new int(*[10])();    // error: parsed as (new int) (*[10]) ()
new (int (*[10])()); // okay: allocates an array of 10 pointers to functions

さらに、type は貪欲に解析されます。宣言子の一部となりうるすべてのトークンが含まれます。

new int + 1; // okay: parsed as (new int) + 1, increments a pointer returned by new int
new int * 1; // error: parsed as (new int*) (1)

new-initializer は、以下の場合を除き、省略可能ではありません。

  • typeプレースホルダが使用されている場合、すなわち、auto または decltype(auto)(C++14以降)、場合によっては制約と組み合わされる場合(C++20以降)
(C++11以降)
  • type にクラステンプレートが使用されており、その引数が推論される必要がある場合。
(C++17以降)
double* p = new double[]{1, 2, 3}; // creates an array of type double[3]
auto p = new auto('c');            // creates a single object of type char. p is a char*
 
auto q = new std::integral auto(1);         // OK: q is an int*
auto q = new std::floating_point auto(true) // ERROR: type constraint not satisfied
 
auto r = new std::pair(1, true); // OK: r is a std::pair<int, bool>*
auto r = new std::vector;        // ERROR: element type can't be deduced

[編集] 動的配列

type が配列型の場合、最初の次元以外のすべての次元は正の整数定数式(C++14まで)変換済み定数式(型は std::size_t(C++14以降)として指定する必要があり、ただし(括弧で囲まれていない構文 (2) および (4) を使用する場合のみ)、最初の次元は整数型、列挙型、または整数型または列挙型への単一の非明示的変換関数を持つクラス型の式(C++14まで)std::size_tに変換可能な任意の式(C++14以降) にすることができます。これは、実行時にサイズが定義される配列を直接作成する唯一の方法であり、そのような配列はしばしば「動的配列」と呼ばれます。

int n = 42;
double a[n][5]; // error
auto p1 = new  double[n][5];  // OK
auto p2 = new  double[5][n];  // error: only the first dimension may be non-constant
auto p3 = new (double[n][5]); // error: syntax (1) cannot be used for dynamic arrays

最初の次元の値(必要に応じて整数型または列挙型に変換される)が負の場合、動作は未定義です。

(C++11まで)

最初の次元を指定する式の値が無効な場合は、以下のとおりです。

  • 式がクラス型ではなく、std::size_t への変換前の値が負の場合。
  • 式がクラス型であり、ユーザー定義変換関数後の std::size_t への変換前の値が負の場合。
  • 式の値が、実装定義の制限を超える場合。
  • 値が、波括弧で囲まれた初期化子リストで提供される配列要素数(文字列リテラルでの終端の '\0' を含む)よりも小さい場合。

いずれかの理由で最初の次元の値が無効な場合、

  • std::size_t に変換した後、最初の次元がコア定数式であり、かつ潜在的に評価される場合、プログラムはill-formed(不正な形式)です。
  • それ以外の場合、呼び出されるメモリ確保関数が非例外を投げる(noexcept と宣言されていない std::nothrow オーバーロードを含む)場合、new 式は必要な結果型のヌルポインタを返します。
  • それ以外の場合、new 式はメモリ確保関数を呼び出さず、代わりに ハンドラの型が std::bad_array_new_length と一致する例外をスローします。
(C++11以降)

最初の次元がゼロであることは許容され、メモリ確保関数が呼び出されます。

new-initializer が波括弧で囲まれた初期化子リストであり、最初の次元が潜在的に評価されるコア定数式でない場合、空の初期化子リストから仮の配列要素をコピー初期化する際の意味論的制約がチェックされます。

(C++11以降)

[編集] メモリ確保

new 式は、適切なメモリ確保関数を呼び出すことによってメモリを確保します。type が非配列型の場合、関数の名前は operator new です。 type が配列型の場合、関数の名前は operator new[] です。

メモリ確保関数で説明されているように、C++プログラムはこれらの関数のグローバルおよびクラス固有の代替を提供できます。new 式がオプションの :: 演算子で始まる場合(例: ::new T または ::new T[n])、クラス固有の代替は無視されます(関数はグローバルスコープ検索されます)。それ以外の場合、T がクラス型であれば、T のクラススコープから検索が開始されます。

メモリ確保関数を呼び出す際、new 式は要求されたバイト数を std::size_t 型の最初の引数として渡します。これは、非配列 T の場合の sizeof(T) に正確に相当します。

配列のメモリ確保は、未指定のオーバーヘッドを供給する場合があります。これは、メモリ確保関数が標準の非確保形式でない限り、new の呼び出しごとに異なる場合があります。new 式によって返されるポインタは、メモリ確保関数によって返されるポインタからその値だけオフセットされます。多くの実装では、配列のオーバーヘッドを使用して配列内のオブジェクト数を格納しており、これは delete[] 式が適切な数のデストラクタを呼び出すために使用されます。さらに、new 式が charunsigned char、または std::byte の配列を確保するために使用される場合(C++17以降)、配置されるオブジェクトの正しいアラインメントを保証するために、後で確保された配列に配置される場合、必要に応じてメモリ確保関数に追加のメモリを要求する場合があります。

new 式は、置換可能なメモリ確保関数によるメモリ確保を省略または結合することが許可されています。省略の場合、ストレージはメモリ確保関数を呼び出さずにコンパイラによって提供される場合があります(これは未使用の new 式の最適化も可能にします)。結合の場合、newE1 によるメモリ確保は、別の newE2 の追加ストレージを提供するために拡張される場合があります。ただし、以下のすべてが真である場合。

1) E1 によって確保されたオブジェクトの生存期間は、E2 によって確保されたオブジェクトの生存期間を厳密に包含する。
2) E1 および E2 は、同じ置換可能なグローバルメモリ確保関数を呼び出す。
3) 例外を投げるメモリ確保関数の場合、E1 および E2 での例外は、同じハンドラで最初にキャッチされる。

この最適化は、new 式が使用されている場合にのみ許可されることに注意してください。置換可能なメモリ確保関数を呼び出す他の方法ではありません。delete[] new int[10]; は最適化される可能性がありますが、operator delete(operator new(10)); はそうではありません。

(C++14以降)

定数式の評価中、メモリ確保関数の呼び出しは常に省略されます。定数式で評価できるのは、それ以外の場合は置換可能なグローバルメモリ確保関数を呼び出すことになる new 式のみです。

(C++20以降)

[編集] 配置 new

placement-args が提供されている場合、それらは追加の引数としてメモリ確保関数に渡されます。そのようなメモリ確保関数は、「配置 new」として知られています。標準のメモリ確保関数 void* operator new(std::size_t, void*) の後にこれらが続きます。この関数は、2番目の引数を変更せずにそのまま返します。これは、確保されたメモリ内にオブジェクトを構築するために使用されます。

// within any block scope...
{
    // Statically allocate the storage with automatic storage duration
    // which is large enough for any object of type “T”.
    alignas(T) unsigned char buf[sizeof(T)];
 
    T* tptr = new(buf) T; // Construct a “T” object, placing it directly into your 
                          // pre-allocated storage at memory address “buf”.
 
    tptr->~T();           // You must **manually** call the object's destructor
                          // if its side effects is depended by the program.
}                         // Leaving this block scope automatically deallocates “buf”.

注意: この機能は、Allocator クラスのメンバ関数によってカプセル化されています。

アラインメント要件が __STDCPP_DEFAULT_NEW_ALIGNMENT__ を超えるオブジェクト、またはそのようなオブジェクトの配列を確保する場合、new 式はアラインメント要件を(std::align_val_t にラップして)メモリ確保関数の2番目の引数として渡します(配置形式の場合、placement-arg はアラインメントの後に、3番目、4番目などの引数として現れます)。オーバーロード解決に失敗した場合(クラス固有のメモリ確保関数が異なるシグネチャで定義されているため、グローバル関数を隠蔽する場合)、アラインメントを引数リストに含めずにオーバーロード解決が再度試行されます。これにより、アラインメントを認識しないクラス固有のメモリ確保関数が、グローバルなアラインメントを認識するメモリ確保関数よりも優先されるようになります。

(C++17以降)
new T;      // calls operator new(sizeof(T))
            // (C++17) or operator new(sizeof(T), std::align_val_t(alignof(T))))
new T[5];   // calls operator new[](sizeof(T)*5 + overhead)
            // (C++17) or operator new(sizeof(T)*5+overhead, std::align_val_t(alignof(T))))
new(2,f) T; // calls operator new(sizeof(T), 2, f)
            // (C++17) or operator new(sizeof(T), std::align_val_t(alignof(T)), 2, f)

非例外を投げるメモリ確保関数(例: new(std::nothrow) T で選択されるもの)がメモリ確保の失敗によりヌルポインタを返した場合、new 式は直ちに返り、オブジェクトの初期化や解放関数の呼び出しは行いません。ヌルポインタが非確保の配置 new 式の引数として渡され、選択された標準の非確保配置メモリ確保関数がヌルポインタを返す場合、動作は未定義です。

[編集] 初期化

new 式によって作成されたオブジェクトは、以下の規則に従って初期化されます。

type が配列型でない場合、単一のオブジェクトは取得されたメモリ領域に構築されます。

  • new-initializer が存在しない場合、オブジェクトはデフォルト初期化されます。
  • new-initializer が丸括弧で囲まれた式リストの場合、オブジェクトは直接初期化されます。
  • new-initializer が波括弧で囲まれた初期化子リストの場合、オブジェクトはリスト初期化されます。
(C++11以降)

type が配列型の場合、オブジェクトの配列が初期化されます。

  • 最初の次元がゼロであっても、仮の要素のデフォルト初期化の意味論的制約を満たす必要があります。
  • new-initializer が丸括弧のペアの場合、各要素は値初期化されます。
  • 最初の次元がゼロであっても、仮の要素の値初期化の意味論的制約を満たす必要があります。
  • new-initializer が波括弧で囲まれた初期化子リストの場合、配列は集約初期化されます。
(C++11以降)
  • new-initializer が丸括弧で囲まれた非空の式リストの場合、配列は集約初期化されます。
(C++20以降)

[編集] 初期化の失敗

初期化が例外をスローして終了した場合(例: コンストラクタから)、プログラムは一致する解放関数を検索し、次に

  • 適切な解放関数が見つかった場合、解放関数が呼び出されてオブジェクトが構築されていたメモリが解放されます。その後、例外は new 式のコンテキストで伝播し続けます。
  • 一意に一致する解放関数が見つからない場合、例外の伝播はオブジェクトのメモリを解放しません。これは、呼び出されたメモリ確保関数がメモリを確保しない場合にのみ適切であり、それ以外の場合はメモリリークにつながる可能性が高いです。

一致する解放関数の検索のスコープは、次のように決定されます。

  • new 式が :: で始まらず、確保された型がクラス型 T またはクラス型 T の配列のいずれかである場合、T のクラススコープで解放関数の名前が検索されます。
  • それ以外の場合、または T のクラススコープで見つからなかった場合、解放関数の名前はグローバルスコープで検索することによって検索されます。

非配置メモリ確保関数の場合、通常の解放関数検索を使用して一致する解放関数が見つかります(delete 式を参照)。

配置メモリ確保関数の場合、一致する解放関数は、パラメータの数が同じであり、最初のパラメータ以外の各パラメータの型が、メモリ確保関数の対応するパラメータの型と(パラメータ変換後)同一でなければなりません。

  • 検索で単一の一致する解放関数が見つかった場合、その関数が呼び出されます。それ以外の場合は、解放関数は呼び出されません。
  • 検索で非配置解放関数が見つかり、その関数が配置解放関数として考慮された場合にメモリ確保関数に一致するものとして選択された場合、プログラムはill-formed(不正な形式)です。

いずれの場合も、一致する解放関数(存在する場合)は非削除であり(C++11以降)new 式が登場する場所からアクセス可能でなければなりません。

struct S
{
    // Placement allocation function:
    static void* operator new(std::size_t, std::size_t);
 
    // Non-placement deallocation function:
    static void operator delete(void*, std::size_t);
};
 
S* p = new (0) S; // error: non-placement deallocation function matches
                  //        placement allocation function

解放関数が new 式で呼び出された場合(初期化失敗のため)、その関数に渡される引数は次のように決定されます。

  • 最初の引数は、メモリ確保関数呼び出しから返された値(型は void*)です。
  • その他の引数(配置解放関数のみ)は、配置メモリ確保関数に渡された placement-args です。

実装がメモリ確保関数への呼び出しの一部として一時オブジェクトを導入したり、引数のコピーを作成したりすることが許可されている場合、割り当て関数と解放関数の両方の呼び出しで同じオブジェクトが使用されるかどうかは未指定です。

[編集] メモリリーク

new 式によって作成されたオブジェクト(動的記憶域期間を持つオブジェクト)は、new 式によって返されたポインタが対応するdelete 式で使用されるまで存続します。ポインタの元の値が失われた場合、オブジェクトは到達不能になり、解放できなくなります。これにより、メモリリークが発生します。

これは、ポインタが次の場合に発生する可能性があります。

int* p = new int(7); // dynamically allocated int with value 7
p = nullptr; // memory leak

ポインタが代入された場合。

void f()
{
    int* p = new int(7);
} // memory leak

ポインタがスコープを外れた場合。

void f()
{
    int* p = new int(7);
    g();      // may throw
    delete p; // okay if no exception
} // memory leak if g() throws

例外による場合。

動的に確保されたオブジェクトの管理を容易にするために、new 式の結果はしばしばスマートポインタに格納されます。 std::auto_ptr(C++17まで)std::unique_ptr、または std::shared_ptr(C++11以降)。これらのポインタは、上記の場合にdelete式が確実に実行されることを保証します。

[編集] 注記

Itanium C++ ABI は、作成される配列の要素型がトリビアルに破棄可能である場合、配列のメモリ確保オーバーヘッドはゼロである必要があることを要求しています。MSVCも同様です。

一部の実装(例: VS 2019 v16.7 より前の MSVC)では、要素型がトリビアルに破棄可能でない非確保配置配列 new で、非ゼロの配列メモリ確保オーバーヘッドが必要でしたが、これは CWG issue 2382 以降、準拠しなくなっています。

unsigned char、または std::byte の配列を作成する非確保配置配列 new(C++17以降) は、指定されたメモリ領域にオブジェクトを暗黙的に作成するために使用できます。これは、配列と重複するオブジェクトの生存期間を終了させ、次に配列内に暗黙的生存期間を持つ型のオブジェクトを暗黙的に作成します。

std::vector は、一次元動的配列に対して同様の機能を提供します。

new

[編集] キーワード

以下の動作変更を伴う欠陥報告が、以前に公開されたC++標準に遡って適用されました。

DR 適用対象 公開された動作 正しい動作
[編集] 不具合報告 C++98 CWG 74 最初の次元の値は整数型でなければならない
列挙型も許可される C++98 CWG 299
最初の次元の値は
整数型または列挙型である必要がある
整数型または列挙型への単一の
変換関数を持つクラス型も許可される
CWG 624 C++98 確保されるオブジェクトのサイズが
実装定義の制限を超える場合
動作が未指定であった
この場合、ストレージは取得されず、
例外がスローされる
CWG 1748 C++98 非確保配置 new は
引数が null かどうかをチェックする必要がある
null 引数に対する未定義の動作
CWG 1992 C++11 new(std::nothrow) int[N]
std::bad_array_new_length をスローする可能性があった
ヌルポインタを返すように変更された
CWG 2102 C++98 空の配列の初期化時に
デフォルト/値初期化が必要かどうか不明確だった
必要
CWG 2382 C++98 非確保配置配列 new は
メモリ確保オーバーヘッドを必要とする可能性があった
そのようなメモリ確保オーバーヘッドは禁止された
CWG 2392 C++11 最初の次元が潜在的に評価されない場合でも
プログラムがill-formedになる可能性があった
この場合、well-formed
P1009R2 C++11 配列の境界を
new 式で推論できなかった
推論が許可されるようになった

[編集] 関連項目

English 日本語 中文(简体) 中文(繁體)