C++ の new 演算子

C++new 演算子は、動 的ストレージ割り振りを提供します。 new 演算子を含む割り振り式の構文は、次のとおりです。

>>-+----+--new--+---------------------+--+-(--type--)-+--------->
   '-::-'       '-(--argument_list--)-'  '-new_type---'
 
>--+-------------------------+---------------------------------><
   '-(--+---------------+--)-'
        '-initial_value-'
 
 

スコープ・レゾリューション演算子 (::) に new を接頭部として付けると、global operator new() が使用されます。 argument_list を指定した場合は、その argument_list に対応する、 多重定義された new 演算子が使われます。 type は、既存のインクルード型またはユーザー定義の型です。 new_type は、まだ定義されていない型で、 型指定子と宣言子をインクルードすることができます。

new 演算子を含む割り振り式は、作成されたオブジェクトのフリー・ストアのストレージ を検出するために使われます。 new 式 は、作成されたオブジェクトを指すポインターを戻し、 これを使用してオブジェクトを初期化することができます。 オブジェクトが配列の場合は、 最初のエレメントを指すポインターが戻されます。

set_new_handler() は、new が失敗したときに、 それが何をするかを指定するためにだけ使用することができます。

関数型、void、または不完全クラス型はオブジェクトの型ではないので 、new 演算子を使用してこれらの型を割り振ることはできません。ただし、new 演算子を 使用して、関数を指すポインターを割り振ることはできます。new 演算子を使用して、 参照を作成することはできません。

作成されるオブジェクトが配列の場合は、最初の次元だけが汎用式になります。 以降のすべての次元は、整数定数式でなければなりません。 最初の次元は、既存の type が使われているときにも、汎用式になります。 new 演算子を使用して、ゼロ境界付きの配列を作成できます。 次に例を示します。

char * c = new char[0];

この場合、固有なオブジェクトへのポインターが戻されます。

operator new() または operator new[]() を使用して作成されたオブジェクトは、operator delete() または operator delete[]() が、 オブジェクトのメモリーを割り振り解除するために呼び出されるまで、存在します。 delete 演算子またはデストラクターは、new を使用して作成されたオブジェクトで、 プログラムの終了の前に明示的に割り振り解除されていないものに対して、暗黙的に呼び出されることはありません。

小括弧が new 型内で使用される場合、構文エラーを避けるために、 その new 型も小括弧で囲む必要があります。

次の例では、関数を指すポインターの配列用ストレージが割り振られます。

void f();
void g();
 
int main(void)
{
      void (**p)(), (**q)();
      // declare p and q as pointers to pointers to void functions
      p = new (void (*[3])());
      // p now points to an array of pointers to functions
      q = new void(*[3])(); // error
      // error - bound as 'q = (new void) (*[3])();'
      p[0] = f;  // p[0] to point to function f
      q[2] = g;  // q[2] to point to function g
      p[0]();    // call f()
      q[2]();    // call g()
      return (0);
}

ただし、2 番目の new の使用では、 q = (new void) (*[3])() のように間違ったバインディングになります。

作成されるオブジェクトの型には、クラス宣言、列挙宣言、const 型、または volatile 型を 含めることはできません。const または volatile オブジェクトを指すポインターは 含めることができます。

例えば、const char* は使用できますが、char* const は使用できません。

配置構文

割り振り保管場所を指定する 引き 数は、argument_list を使用することによって、new に引き数を追加する ことが できます (配置構文 とも呼ばれます)。

配置引き数を使う場合は、それらの引き数が指定された operator new() または operator new[]() が宣言されていなければなりません。 次に例を示します。

#include <new>
using namespace std;
 
class X
{
public:
      void* operator new(size_t,int, int){ /* ... */ }
};
 
// ...
 
int main ()
{
      X* ptr = new(1,2) X;
}

配置構文は通常、グローバル配置 new 関数を呼び出すときに使用されます。 グローバル配置 new 関数は、new 式の配置引き数に指定されたロケーションのオブジェクト (1 つまたは複数) を 初期化します。 グローバル配置 new 関数はそれ自体にメモリーを割り振ることはしないので、このロケーションには他の方法で 事前に割り振られていたストレージをアドレッシングしなければなりません。 次の例では、new(whole) X(8);new(seg2) X(9);、または new(seg3) X(10); を 呼び出しても新規メモリーは割り振られません。代わりに、コンストラクター X(8)X(9)、 および X(10) を呼び出して、バッファー whole に割り振られたメモリーを再初期化します。

new はメモリーを割り振らないので、配置構文で作成されたオブジェクトを割り振 り解除する際に、delete を使用するべきではありません。 メモリー・プール全体の削除だけが可能です (delete whole)。 この例では、メモリー・バッファーは保持できますが、明示的にデストラクターを呼び出すことにより、そこに 保管されているオブジェクトは破棄されます。

#include <new>
class X
{
   public:
      X(int n): id(n){ }
      ~X(){ }
   private:
      int id;
      //	...
};
 
int main()
{
   char* whole = new char[ 3 * sizeof(X) ];  // a 3-part buffer
   X * p1 = new(whole) X(8);                 // fill the front
   char* seg2 = &whole[ sizeof(X) ];         // mark second segment
   X * p2 = new(seg2) X(9);                  // fill second segment
   char* seg3 = &whole[ 2 * sizeof(X) ];     // mark third segment
   X * p3 = new(seg3) X(10);                 // fill third segment
 
   p2->~X();   // clear only middle segment, but keep the buffer
   // ...
   return 0;
}
new 配置構文は、コンストラクターではなく割り振りルーチンにパラメーター を渡す場合にも使用できます。

関連参照

IBM Copyright 2003