new
演算子 (C++)
指定された、またはプレースホルダーの型のオブジェクトまたはオブジェクトの配列を割り当てて初期化することを試行し、適切に型指定されたゼロ以外のポインターをオブジェクト (または配列の初期オブジェクト) に返します。
構文
new-expression
=
::
optnew
new-placement
optnew-type-id
new-initializer
opt
::
optnew
new-placement
opt(
type-id
)
new-initializer
opt
new-placement
=
(
expression-list
)
new-type-id
=
type-specifier-seq
new-declarator
opt
new-declarator
=
ptr-operator
new-declarator
opt
noptr-new-declarator
noptr-new-declarator
=
[
expression
]
attribute-specifier-seq
opt
noptr-new-declarator
[
constant-expression
]
attribute-specifier-seq
opt
new-initializer
=
(
expression-list
opt)
braced-init-list
解説
失敗した場合、new
からは 0 が返されるか、または例外がスローされます。 詳細については、new
および delete
演算子に関するページを参照してください。 カスタム例外処理ルーチンを作成し、_set_new_handler
ランタイム ライブラリ関数を呼び出して、その引数として関数名を渡すことで、この既定のビヘイビアーを変更できます。
C++/CLI および C++/CX マネージド ヒープにオブジェクトを作成する方法については、gcnew に関するページを参照してください。
Note
Microsoft C++ Component Extensions (C++/CX) では、new
キーワードによる vtable スロット エントリの追加がサポートされています。 詳細については、「new
(vtable の新しいスロット)」を参照してください
new
を使用してメモリを C++ クラス オブジェクトに割り当てると、メモリの割り当て後に、そのオブジェクトのコンストラクターが呼び出されます。
new
演算子によって割り当てられたメモリの割り当てを解除するには、delete
演算子を使用します。 new
演算子によって割り当てられた配列を削除するには、delete[]
演算子を使用します。
次の例では、サイズ dim
× 10 の文字の 2 次元配列を割り当てた後、解放します。 多次元配列を割り当てる場合、最初のディメンションを除くあとのディメンションはすべて、正の値に評価される定数式である必要があります。 左端の配列のディメンションには、正の値に評価される任意の式を指定できます。 new
演算子を使用して配列を割り当てるとき、最初のディメンションはゼロでかまいません。new
演算子からユニーク ポインターが返されます。
char (*pchar)[10] = new char[dim][10];
delete [] pchar;
type-id
に const
、volatile
、クラス宣言、または列挙体宣言を含めることはできません。 次の式は形式が正しくありません。
volatile char *vch = new volatile char[20];
参照型はオブジェクトでないため、new
演算子で割り当てられることはありません。
new
演算子は、関数の割り当てには使用できませんが、関数へのポインターの割り当てには使用できます。 次の例では、整数を返す関数への 7 個のポインターの配列を割り当てた後、解放します。
int (**p) () = new (int (*[7]) ());
delete p;
余分な引数を付けずに new
演算子を使用し、/GX
、/EHa
、または /EHs
オプションを指定してコンパイルする場合、コンストラクターが例外をスローしたときに delete
演算子を呼び出すコードが、コンパイラによって生成されます。
次の一覧では、new
の文法要素について説明します。
new-placement
new
をオーバーロードする場合、追加の引数を渡す方法を指定します。
type-id
割り当てる型を指定します。組み込みまたはユーザー定義の型を指定できます。 型の指定が複雑な場合には、かっこで囲むことでバインディング順を強制的に適用できます。 型はプレースホルダー (auto
) とすることもできます。コンパイラによってその型が決定されます。
new-initializer
初期化されたオブジェクトの値を指定します。 初期化子は配列には指定できません。 new
演算子は、クラスに既定のコンストラクターがある場合のみ、オブジェクトの配列を生成します。
noptr-new-declarator
配列の境界を指定します。 多次元配列を割り当てる場合、最初のディメンションを除くあとのディメンションはすべて、std::size_t
に変換可能な正の値に評価される定数式とする必要があります。 左端の配列のディメンションには、正の値に評価される任意の式を指定できます。 attribute-specifier-seq
は、関連付けられている配列型に適用されます。
例: 文字配列の割り当てと解放
次のコード例では、文字配列と CName
クラスのオブジェクトを割り当てた後、解放します。
// expre_new_Operator.cpp
// compile with: /EHsc
#include <string.h>
class CName {
public:
enum {
sizeOfBuffer = 256
};
char m_szFirst[sizeOfBuffer];
char m_szLast[sizeOfBuffer];
public:
void SetName(char* pszFirst, char* pszLast) {
strcpy_s(m_szFirst, sizeOfBuffer, pszFirst);
strcpy_s(m_szLast, sizeOfBuffer, pszLast);
}
};
int main() {
// Allocate memory for the array
char* pCharArray = new char[CName::sizeOfBuffer];
strcpy_s(pCharArray, CName::sizeOfBuffer, "Array of characters");
// Deallocate memory for the array
delete [] pCharArray;
pCharArray = NULL;
// Allocate memory for the object
CName* pName = new CName;
pName->SetName("Firstname", "Lastname");
// Deallocate memory for the object
delete pName;
pName = NULL;
}
例: new
演算子
new
演算子の配置形式 (サイズよりも多くの引数を持つ形式) を使用する場合、コンストラクターから例外がスローされると、コンパイラでは delete
演算子の配置形式がサポートされません。 次に例を示します。
// expre_new_Operator2.cpp
// C2660 expected
class A {
public:
A(int) { throw "Fail!"; }
};
void F(void) {
try {
// heap memory pointed to by pa1 will be deallocated
// by calling ::operator delete(void*).
A* pa1 = new A(10);
} catch (...) {
}
try {
// This will call ::operator new(size_t, char*, int).
// When A::A(int) does a throw, we should call
// ::operator delete(void*, char*, int) to deallocate
// the memory pointed to by pa2. Since
// ::operator delete(void*, char*, int) has not been implemented,
// memory will be leaked when the deallocation can't occur.
A* pa2 = new(__FILE__, __LINE__) A(20);
} catch (...) {
}
}
int main() {
A a;
}
new
で割り当てたオブジェクトの初期化
オプションの new-initializer
フィールドは、new
演算子の文法に含まれます。 このフィールドにより、新しいオブジェクトをユーザー定義コンストラクターで初期化できます。 初期化の実行方法の詳細については、「初期化子」を参照してください。 次の例では、new
演算子で初期化式を使用する方法を説明します。
// expre_Initializing_Objects_Allocated_with_new.cpp
class Acct
{
public:
// Define default constructor and a constructor that accepts
// an initial balance.
Acct() { balance = 0.0; }
Acct( double init_balance ) { balance = init_balance; }
private:
double balance;
};
int main()
{
Acct *CheckingAcct = new Acct;
Acct *SavingsAcct = new Acct ( 34.98 );
double *HowMuch = new double { 43.0 };
// ...
}
この例では、オブジェクト CheckingAcct
は new
演算子を使用して割り当てられますが、既定値の初期化は指定されません。 そのため、Acct()
クラスの既定のコンストラクターが呼び出されます。 その後、オブジェクト SavingsAcct
は、同じように割り当てられます。ただし、明示的に 34.98 に初期化されます。 34.98 は double
型であるため、初期化を処理するために、その型の引数を受け取るコンストラクターが呼び出されます。 最後に、HowMuch
非クラス型は 43.0 に初期化されます。
オブジェクトがクラス型で、(前の例のように) そのクラスにコンストラクターがある場合、次の条件の 1 つが満たされる場合にのみオブジェクトを new
演算子で初期化できます。
初期化子内に指定された引数は、コンストラクターの引数と一致します。
クラスには、既定のコンストラクター (引数を指定せずに呼び出すことができるコンストラクター) があります。
new
演算子を使用して配列を割り当てる場合は、明示的な要素ごとの初期化は実行できません。既定のコンストラクターがあれば、このコンストラクターのみ呼び出されます。 詳細については、「既定の引数」をご覧ください。
メモリの割り当てに失敗すると (operator new
から値 0 が返される)、初期化は行われません。 この動作により、存在しないデータを初期化しようとする試みを防止できます。
関数呼び出しの場合と同様に、初期化された式が評価される順序は定義されていません。 さらに、メモリの割り当てが実行される前にこれらの式が完全に評価されることを、頼りにしないでください。 メモリの割り当てに失敗し、new
演算子がゼロを返すと、初期化子の一部の式は完全に評価されない場合があります。
new
で割り当てたオブジェクトの有効期間
new
演算子によって割り当てられたオブジェクトは、それが定義されているスコープが終了しても破棄されません。 new
演算子は割り当てたオブジェクトへのポインターを返すため、プログラムでは、これらのオブジェクトにアクセスして削除するための適切なスコープを持つポインターを定義する必要があります。 次に例を示します。
// expre_Lifetime_of_Objects_Allocated_with_new.cpp
// C2541 expected
int main()
{
// Use new operator to allocate an array of 20 characters.
char *AnArray = new char[20];
for( int i = 0; i < 20; ++i )
{
// On the first iteration of the loop, allocate
// another array of 20 characters.
if( i == 0 )
{
char *AnotherArray = new char[20];
}
}
delete [] AnotherArray; // Error: pointer out of scope.
delete [] AnArray; // OK: pointer still in scope.
}
この例では、ポインター AnotherArray
がスコープ外になると、オブジェクトを削除できなくなります。
new
の動作のしくみ
new-expression
(new
演算子を含む式) では次の 3 つのことを行います。
割り当てられるオブジェクトのストレージを探し、予約します。 この段階が完了すると、適切なサイズのストレージが割り当てられます。ただし、まだオブジェクトではありません。
オブジェクトを初期化します。 初期化が完了すると、割り当てられたストレージをオブジェクトにするための十分な情報が得られます。
new-type-id
またはtype-id
から派生したポインター型のオブジェクトへのポインターを返します。 プログラムでは、このポインターを使用して新しく割り当てられたオブジェクトにアクセスします。
new
演算子を使用すると、operator new
関数が呼び出されます。 任意の型の配列の場合、または class
型、struct
型、union
型ではないオブジェクトの場合、::operator new
グローバル関数を呼び出してストレージを割り当てます。 クラス型オブジェクトを使用すると、クラスごとに異なる operator new
静的メンバー関数を定義できます。
コンパイラは、T
型のオブジェクトを割り当てるための new
演算子を検出すると、T::operator new( sizeof(T) )
または (ユーザー定義の operator new
が定義されていない場合) ::operator new( sizeof(T) )
の呼び出しを発行します。 これは、new
演算子を使用してオブジェクトに適したサイズのメモリを割り当てる方法です。
Note
operator new
の引数は std::size_t
型です。 この型は、<direct.h>、<malloc.h>、<memory.h>、<search.h>、<stddef.h>、<stdio.h>、<stdlib.h>、<string.h>、<time.h>で定義されます。
必要であれば new-placement
も指定できます (new
演算子の文法を参照してください)。 new-placement
パラメーターは operator new
のユーザー定義の実装にのみ使用できます。これは、追加情報が operator new
に渡されることを許可します。 T *TObject = new ( 0x0040 ) T;
のように new-placement
フィールドが指定された式は、クラス T がメンバー operator new
を持つ場合は T *TObject = T::operator new( sizeof( T ), 0x0040 );
に変換されます。その以外の場合は T *TObject = ::operator new( sizeof( T ), 0x0040 );
に変換されます。
new-placement
フィールドの本来の意図は、ハードウェアに依存するオブジェクトをユーザー指定のアドレスに割り当てられるようにすることです。
Note
前の例では new-placement
フィールドに引数を 1 つだけ指定しましたが、この方法で operator new
に渡すことができる引数の数に制限はありません。
クラス型 T
に対して operator new
が定義されている場合でも、次の例のように、グローバル演算子 new
を明示的に使用できます。
T *TObject = ::new TObject;
スコープ解決演算子 (::
) を使用する場合は、グローバルの new
演算子を使用する必要があります。
関連項目
フィードバック
https://aka.ms/ContentUserFeedback」を参照してください。
以下は間もなく提供いたします。2024 年を通じて、コンテンツのフィードバック メカニズムとして GitHub の issue を段階的に廃止し、新しいフィードバック システムに置き換えます。 詳細については、「フィードバックの送信と表示