web-dev-qa-db-ja.com

ポインターコンテナーでC ++ 11 emplace_backを使用する必要がありますか?

通常のベース->派生階層:

class Fruit { ... };
class Pear : Fruit { ... };
class Tomato : Fruit { ... };

std::vector<Fruit*> m_fruits;

Push_backの代わりにemplace_backを使用することは理にかなっていますか(たとえば、パフォーマンスが優れています)。

std::vector::emplace_back( new Pear() );
std::vector::emplace_back( new Tomato() );
20
Zhen

ポインターはスカラー型であるため、リテラル型であるため、(左辺値または右辺値からの)コピー、移動、配置の構築はすべて同等であり、通常は同じコードにコンパイルされます(スカラーコピー)。 _Push_back_は、スカラーコピーを実行していることが明確ですが、_emplace_back_は、非コピーコンストラクターまたは移動コンストラクター(例:変換コンストラクターまたは複数引数コンストラクター)を呼び出すエンプレース構築用に予約する必要があります。

ベクターが生のポインターの代わりに_std::unique_ptr<Fruit>_を保持する必要がある場合(メモリリークを防ぐため)、変換コンストラクター_emplace_back_を呼び出すため、より正確になります。ただし、ベクトルの拡張に失敗した場合でもリークする可能性があるため、その場合はPush_back(make_unique<Pear>())などを使用する必要があります。

16
ecatmur

生のポインタを使用せず、std::unique_ptrを次のように使用します。

std::vector<std::unique_ptr<Fruit>> m_fruits;

また、構造体std::unique_ptrはコピーできないため、emplace_backを使用する必要があります(Push_backstd::moveは併用できます)。


 m_fruits.emplace_back(new Pear()); 
 m_fruits.emplace_back(new Tomato()); 

編集:

std::vector<std::unique_ptr<T>>::emplace_backが必要でメモリの再割り当てに失敗した場合、std::vectorおよびnewを使用するとリークする可能性があるため、私の推奨するアプローチ(C++ 14がstd::make_uniqueを導入するまで)はこのようにPush_backを使用するには:

m_fruits.Push_back(std::unique_ptr<Fruit>(new Pear));
m_fruits.Push_back(std::unique_ptr<Fruit>(new Tomato));

またはstd::make_uniqueを使用:

m_fruits.Push_back(std::make_unique<Pear>());
m_fruits.Push_back(std::make_unique<Tomato>());
21
Snps