2

私の質問は、Scott Meyer の本「より効果的な C++ 35 の新しい方法 ...」のコード スナップショットに関するものです。

コード (パラメータ名が変更されます)

void * memory = operator new[] (10*sizeOf(MyClass));
MyClass * myArray = static_cast<MyClass*>(memory);
for(int i= 0; i<10; i++)
{
new (&myArray[i]) MyClass(params);
}

私はこの構文に慣れていません。演算子 new [] と new (&myArray[i]) でさえ...その構文、それらがどのように機能しているかについて詳しく読むことができるリソースはありますか。

4

4 に答える 4

2

これを理解するには、まず単純で単純なnew仕組みを理解する必要があります。式の通常の構文newは次のようなものnew Tです。式を使用するnewと、次のことが起こります。

  1. まず、割り当て関数を呼び出して、オブジェクトのストレージを取得します。割り当て関数は、要求されたオブジェクトに適合するのに十分な大きさの割り当てられたストレージへのポインターを返す必要があります。これ以上のことはしません。オブジェクトを初期化しません。

  2. 次に、割り当てられた領域でオブジェクトが初期化されます。

  3. 割り当てられた領域 (および初期化されたオブジェクト) へのポインターが返されます。

の場合new T、割り当て関数の名前はoperator newです。などの配列を割り当てる場合new T[5]、割り当て関数には という名前が付けられoperator new[]ます。これらの関数の既定の定義は、グローバル名前空間で提供されます。std::size_tそれらはそれぞれ、必要なバイト数であるタイプの単一の引数を取ります。したがって、 を実行するnew Tと、対応する呼び出しは になりますが、operator new(sizeof(T))forは呼び出されます。new T[5]operator new[](sizeof(T)*5)

ただし、割り当て関数にさらに多くの引数を渡すことは可能です。これは、配置の新しい構文として知られています。より多くの引数を渡すにはnew (some, arguments, 3) T、 を呼び出すso: のような構文を使用しますoperator new(sizeof(T), some, arguments, 3)new引数のリストは、 と タイプの間の括弧で囲みます。

どちらも実装によって提供される単純なoperator new(std::size_t)配列とそれに対応する配列に加えて、 type の追加の引数を取るデフォルトの定義もありますvoid*。つまり、オブジェクトへのポインタを取ります。これらの関数は実際にはスペースを割り当てず、指定したポインターを返すだけです。したがって、 を実行するnew (some_pointer) Tと、最初に が呼び出さoperator new(sizeof(T), some_pointer)some_pointer、再び戻り、次にその空間でオブジェクトが初期化されます。これにより、すでに割り当てられている領域でオブジェクトを初期化する方法が提供されます。

これで、次の 4 つの定義済み割り当て関数ができました (実際、他にもいくつかあり、独自のものも自由に定義できます)。

// Normal allocation functions that allocate space of the given size
operator new(std::size_t)
operator new[](std::size_t)
// Placement allocation functions that just return the pointer they're given
operator new(std::size_t, void*)
operator new[](std::size_t, void*)

それでは、あなたが提供したコードスニペットを見てみましょう:

void * memory = operator new[] (10*sizeOf(MyClass));
MyClass * myArray = static_cast<MyClass*>(memory);
for(int i= 0; i<10; i++)
{
  new (&myArray[i]) MyClass(params);
}

operator new[]最初の行では、ストレージを割り当てるために直接呼び出しています。収納量は?タイプ のオブジェクトが 10 個あれば十分ですMyClass。この関数は、その割り当てられたストレージへのポインターを返し、それを に格納しますmemory

この後、void*は a にキャストされ、MyClass*サイズ のブロックで割り当てられたストレージにインデックスを付けることができますsizeof(MyClass)。つまりmyArray[0]、最初MyClassmyArray[1]2 番目を指すようになります。

次に、その配列をループし、割り当てられたストレージの初期化されていないサイズの各ビットのアドレスを使用して、placement newを呼び出します。MyClassたとえば、最初の繰り返しでは、これは割り当て関数operator new(sizeof(MyClass), &myArray[0])を呼び出します。これは、前に見たように、指定したポインターを返すだけです。新しい式はMyClass、この空間でオブジェクトを初期化し、ポインタを返すことで完了します。

要約すると、コードは 10 個MyClassのオブジェクトに適合するようにストレージを割り当て (ただし、初期化はしません)、MyClassそのストレージ内の の各サイズのスペースをループして、それぞれのオブジェクトを初期化します。

これは、事前に割り当てられたストレージでオブジェクトを初期化する方法を示しています。新しく初期化されたオブジェクトで同じストレージを何度も再利用できます。

于 2012-11-04T13:01:54.817 に答える
2
void * memory = operator new[] (10*sizeOf(MyClass));

10*sizeOf(MyClass)ここでは sizeバイトのメモリを割り当てます。これは生の初期化されていないメモリです。このメモリには構築された C++ オブジェクトはありません。

new (&myArray[i]) MyClass(params);

ここでは、placement-newを使用して、 が指す特定のメモリ内にオブジェクトを構築します&myArray[i]

placement-new の一般的な構文は次のとおりです。

X * x = new (pAllocatedMem) X(a,b,c);

つまり、コンストラクターに,Xを渡す型のオブジェクトを構築します。オブジェクトは、 が指すメモリに構築されます。abcpAllocatedMem

また、次のように、placement-new を使用して構築されたオブジェクトを削除することにも注意してください。

x->~X(); //delete the constructed object. DONT USE : delete x;

delete xつまり、そのようなオブジェクトを削除する必要はありません。

于 2012-11-04T12:30:15.793 に答える
2

ウィキペディアがあなたの質問に答えます。

1 つ目newは、生メモリを割り当てるためのものです。

http://en.wikipedia.org/wiki/New_(C%2B%2B)#void.2A_operator_new.28size_t_size.29

メモリを割り当てるだけの C++ 言語構造は、void* operator new(size_t size) と呼ばれます。割り当てフェーズで new によって使用されます。クラスごとにオーバーライドして、クラス固有のメモリ アロケータを定義できます。


2 つ目newは、placement new と呼ばれます。

http://en.wikipedia.org/wiki/Placement_new

追加の void * パラメーターを使用する operator new および operator delete の配置オーバーロードは、ポインター配置とも呼ばれる既定の配置に使用されます。

于 2012-11-04T12:30:22.390 に答える
1
new (&myArray[i]) MyClass(params);

配置new演算子です。事前に割り当てられたメモリ位置にオブジェクトを作成できます。

18.4.1.3 配置フォーム

void* 演算子 new(std::size_t size, void* ptr) throw();

戻り値: ptr.
3 注: 意図的に他のアクションを実行しません。
4 [例: これは既知のアドレスでオブジェクトを構築するのに役立ちます:

void* place = operator new(sizeof(Something));

Something* p = new (place) Something();
—end example]

void* operator new[](std::size_t size, void* ptr) throw();

5 Returns: ptr.
6 Notes: Intentionally performs no other action.
于 2012-11-04T12:29:59.847 に答える