new 演算子 (C++)

指定された、またはプレースホルダーの型のオブジェクトまたはオブジェクトの配列を割り当てて初期化することを試行し、適切に型指定されたゼロ以外のポインターをオブジェクト (または配列の初期オブジェクト) に返します。

構文

new-expression=
::optnewnew-placementoptnew-type-idnew-initializeropt
::optnewnew-placementopt(type-id)new-initializeropt

new-placement=
( expression-list )

new-type-id=
type-specifier-seqnew-declaratoropt

new-declarator=
ptr-operatornew-declaratoropt
noptr-new-declarator

noptr-new-declarator=
[expression]attribute-specifier-seqopt
noptr-new-declarator[constant-expression]attribute-specifier-seqopt

new-initializer=
(expression-listopt)
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-idconstvolatile、クラス宣言、または列挙体宣言を含めることはできません。 次の式は形式が正しくありません。

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 };
    // ...
}

この例では、オブジェクト CheckingAcctnew 演算子を使用して割り当てられますが、既定値の初期化は指定されません。 そのため、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 演算子を使用する必要があります。

関連項目

単項演算子を含む式
キーワード
new および delete 演算子