new operator (C++)

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

構文

new-expression:
:: optnewnew-placementoptnew-type-idnew-initializer選ぶ
:: optnewnew-placementopt(type-id)new-initializer選ぶ

new-placement:
( expression-list )

new-type-id:
type-specifier-seq new-declarator 選ぶ

new-declarator:
ptr-operator new-declarator 選ぶ
noptr-new-declarator

noptr-new-declarator:
[ expression ] attribute-specifier-seq 選ぶ
noptr-new-declarator [ constant-expression ] attribute-specifier-seq 選ぶ

new-initializer:
( expression-list 選ぶ)
braced-init-list

注釈

失敗した場合、 new は 0 を返すか、例外をスローします。 詳細については、「new演算子とdelete演算子」を参照してください。 この既定の動作を変更するには、カスタム例外処理ルーチンを記述し、関数名を引数として _set_new_handler ランタイム ライブラリ関数を呼び出します。

C++/CLI および C++/CX でマネージド ヒープ上にオブジェクトを作成する方法については、 gcnew を参照してください。

Microsoft C++ コンポーネント拡張機能 (C++/CX) では、vtable スロット エントリを追加するための new キーワードがサポートされます。 詳細については、「new (vtable の新しいスロット)」を参照してください。

newを使用して C++ クラス オブジェクトのメモリを割り当てると、メモリが割り当てられた後にオブジェクトのコンストラクターが呼び出されます。

delete演算子を使用して、new 演算子によって割り当てられたメモリの割り当てを解除します。 delete[]演算子を使用して、new演算子によって割り当てられた配列を削除します。

次の例では、サイズが 10 dim 文字の 2 次元配列を割り当てて解放します。 多次元配列を割り当てる場合、最初の次元を除くすべての次元は、正の値に評価される定数式である必要があります。 左端の配列次元には、正の値に評価される任意の式を指定できます。 new演算子を使用して配列を割り当てる場合、最初の次元は 0 にすることができます。new演算子は一意のポインターを返します。

char (*pchar)[10] = new char[dim][10];
delete [] pchar;

type-idには、constvolatile、クラス宣言、または列挙宣言を含めることはできません。 次の式は形式が正しくありません。

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演算子の文法には、省略可能なnew-initializer フィールドが含まれています。 このフィールドを使用すると、ユーザー定義コンストラクターを使用して新しいオブジェクトを初期化できます。 初期化の実行方法の詳細については、「 初期化子」を参照してください。 次の例は、 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 に初期化されます。

オブジェクトがクラス型で、そのクラスにコンストラクターがある場合 (前の例のように)、次のいずれかの条件が満たされた場合にのみ、 new 演算子によってオブジェクトを初期化できます。

  • 初期化子で指定された引数は、コンストラクターの引数と一致します。

  • このクラスには、既定のコンストラクター (引数なしで呼び出すことができるコンストラクター) があります。

new演算子を使用して配列を割り当てるときは、要素ごとの明示的な初期化を実行できません。既定のコンストラクター (存在する場合) のみが呼び出されます。 詳細については、「 既定の引数」を参照してください。

メモリの割り当てが失敗した場合 (operator new は 0 の値を返します)、初期化は行われません。 この動作により、存在しないデータを初期化する試行から保護されます。

関数呼び出しと同様に、初期化された式の評価順序は定義されていません。 さらに、メモリ割り当てが行われる前に、これらの式を完全に評価する必要はありません。 メモリ割り当てが失敗し、 new 演算子が 0 を返した場合、初期化子内の一部の式が完全に評価されない可能性があります。

で割り当てられたオブジェクトの有効期間 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を呼び出します。 任意の型の配列、および classstruct、または union 型ではないオブジェクトの場合は、グローバル関数 ::operator newが呼び出されてストレージが割り当てられます。 クラス型オブジェクトは、クラスごとに独自の operator new 静的メンバー関数を定義できます。

コンパイラは、T型のオブジェクトを割り当てるnew演算子を検出すると、T::operator new( sizeof(T) )の呼び出しを発行するか、ユーザー定義のoperator newが定義されていない場合は、::operator new( sizeof(T) )new演算子は、オブジェクトに適切な量のメモリを割り当てる方法です。

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 フィールドの本来の目的は、ユーザーが指定したアドレスでハードウェア依存オブジェクトを割り当てることでした。

前の例では、 new-placement フィールドに 1 つの引数しか表示されませんが、この方法で operator new に渡すことができる追加の引数の数に制限はありません。

クラス型Tに対してoperator newが定義されている場合でも、次の例のように、グローバル演算子newを明示的に使用できます。

T *TObject = ::new TObject;

スコープ解決演算子 (::) は、グローバル new 演算子を強制的に使用します。

こちらも参照ください

単項演算子を含む式
キーワード
new 演算子と delete 演算子