2016-04-29 12 views
3

私はstd::vectorの中にオブジェクトを格納しています。できるだけデストラクタを呼び出さないようにしたいと思います。
私は移動のものでコピーコンストラクタと割り当てを置き換える:私はこのようにそれを初期化していますなぜstd :: vector :: emplaceは、どのコンストラクタも呼び出さずにデストラクタを呼び出すのですか?

class Object 
{ 
    Object(const Object&) = delete; 
    Object(Object&&); 
    Object& operator=(const Object&) = delete; 
    Object& operator=(Object&&); 
    [...] 
}; 

:次に

std::vector<Object> container; 

container.reserve(42) // Reserve a lot in order to be sure it won't be a problem 

、私は(コンストラクターが1つのintパラメータを取る)emplace_backで2つの要素を追加します。

container.emplace_back(1); 
container.emplace_back(3); 

それまではすべて問題ありません。しかし、私はemplaceとの最後の前に要素を挿入したい:

auto it = container.end(); 

it--; // Last position. 
it--; // Before last position. 
container.emplace(it, 2); 

しかし、ここでデストラクタが呼び出されます。

私はValgrindを使って理由を調べようとしましたが、emplace関数が_M_insert_auxを呼び出して私のデストラクタを呼び出しているように見えます。

どうすれば避けることができますか?

+3

デストラクタを少なくとも1回呼び出さずに、これを行う方法を正確にどのように提案しますか? –

+3

'emplace'は' emplace_back'と異なります。 'emplace_back'は新しい要素を作成するだけで、' emplace'は既に指定された位置に構築された要素を扱わなければなりません。 – songyuanyao

+0

@ T.C。これはまさに私の質問です... – Aracthor

答えて

2

これは避けることはできません。これは単にvectorの仕組みです。これは連続した配列です。連続した配列に新しい要素を挿入する唯一の方法は、に移動します。古い要素を削除します。つまり、移動割り当てを使用して新しい位置に移動することを意味します。

ですから、以下のベクトルを持っており、その内容場合:

[5][12][*][16] 

どこに「*」:あなたが第二の要素の後に挿入した場合

[5][12][16] 

、その後、いくつかの点では、これを持っています移動された要素の値です。

次に、emplaceとなります。 emplaceは、明示的にその位置に値を作成します。それはそのためのものです。ただし、3番目の要素にはすでに移動オブジェクトが存在します。移動元の値です。

したがって、このオブジェクトは、が破棄されてになり、新しいオブジェクトをその場所に構築することができます。したがって、デストラクタを呼び出さなければなりません。

emplaceではなくinsertを使用した場合でも、依然としてデストラクタが呼び出されます。しかし、それはinsert関数に渡すオブジェクトのデストラクタになります。

のように、と呼ばれる「特別な」デストラクタが存在するでしょう。

しかし、実際には、デストラクタ呼び出しの数について心配するべきではありません。絶対コストに焦点を当てる。一般的に言えば、移動専用のタイプの場合、移動元の値のデストラクタは安くなります。

+0

私のオブジェクトは 'new []'で構築時に要素を割り当て、破壊時に 'delete []'で破棄します。ヒープ割り当てが重くなる可能性があるので、できるだけ避ける方法を考えました。しかし、あまりにも多分。 – Aracthor

+2

これは何のための動きです。あなたのクラスは、あなたの 'new []'配列の所有権を移動元オブジェクトから移動先オブジェクトに渡す必要があります。これにより、移動元オブジェクトのデストラクタで配列を 'delete []'する必要がなくなり、移動先オブジェクトに新しい配列を 'new []'する必要がなくなります。 –

+0

@MilesBudnekだから、それを削除しないために元のオブジェクトのポインタを 'nullptr'にセットするだけでいいです...助けてくれてありがとう。 – Aracthor

関連する問題