valgrind で多くの調査を行った結果、std::vector は push_back したいオブジェクトのコピーを作成するという結論に達しました。
それは本当に本当ですか?ベクトルは、コピーなしではオブジェクトの参照またはポインタを保持できません?!
ありがとう
はい、std::vector<T>::push_back()
引数のコピーを作成し、ベクトルに格納します。ベクター内のオブジェクトへのポインターを格納する場合は、 のstd::vector<whatever*>
代わりに を作成しますstd::vector<whatever>
。
ただし、ベクトルがそれらへの参照を保持している間、ポインターによって参照されるオブジェクトが有効なままであることを確認する必要があります (RAII イディオムを使用するスマート ポインターが問題を解決します)。
C++11 以降、すべての標準コンテナー ( std::vector
、std::map
など) は移動セマンティクスをサポートしています。つまり、右辺値を標準コンテナーに渡してコピーを回避できるようになりました。
// Example object class.
class object
{
private:
int m_val1;
std::string m_val2;
public:
// Constructor for object class.
object(int val1, std::string &&val2) :
m_val1(val1),
m_val2(std::move(val2))
{
}
};
std::vector<object> myList;
// #1 Copy into the vector.
object foo1(1, "foo");
myList.push_back(foo1);
// #2 Move into the vector (no copy).
object foo2(1024, "bar");
myList.push_back(std::move(foo2));
// #3 Move temporary into vector (no copy).
myList.push_back(object(453, "baz"));
// #4 Create instance of object directly inside the vector (no copy, no move).
myList.emplace_back(453, "qux");
または、さまざまなスマート ポインターを使用して、ほぼ同じ効果を得ることができます。
std::unique_ptr
例
std::vector<std::unique_ptr<object>> myPtrList;
// #5a unique_ptr can only ever be moved.
auto pFoo = std::make_unique<object>(1, "foo");
myPtrList.push_back(std::move(pFoo));
// #5b unique_ptr can only ever be moved.
myPtrList.push_back(std::make_unique<object>(1, "foo"));
std::shared_ptr
例
std::vector<std::shared_ptr<object>> objectPtrList2;
// #6 shared_ptr can be used to retain a copy of the pointer and update both the vector
// value and the local copy simultaneously.
auto pFooShared = std::make_shared<object>(1, "foo");
objectPtrList2.push_back(pFooShared);
// Pointer to object stored in the vector, but pFooShared is still valid.
はい、std::vector
コピーを保存します。オブジェクトの予想寿命をどのように知る必要vector
がありますか?
オブジェクトの所有権を譲渡または共有する場合は、リソース管理を容易にするためshared_ptr
に ( BoostまたはTR1にある)ようなスマート ポインターを使用します。
std::vector は常に、ベクターに格納されているもののコピーを作成します。
ポインターのベクトルを保持している場合、ポインターのコピーは作成されますが、ポインターが指しているインスタンスは作成されません。大きなオブジェクトを扱っている場合は、常にポインターのベクトルを使用できます (おそらく使用する必要があります)。多くの場合、適切な型のスマート ポインターのベクトルを使用することは、安全のためには有効です。
std::vector は、プッシュバックするもののコピーを作成するだけでなく、コレクションの定義では、コピーを作成すること、およびベクター内で正しいコピー セマンティクスを持たないオブジェクトを使用できないことを示しています。したがって、たとえば、ベクターでは auto_ptr を使用しません。
C++11 に関連するのはemplace
、オブジェクトをコンテナーに移動することでオブジェクトの所有権を譲渡できるメンバー関数のファミリーです。
使用法のイディオムは次のようになります
std::vector<Object> objs;
Object l_value_obj { /* initialize */ };
// use object here...
objs.emplace_back(std::move(l_value_obj));
左辺値オブジェクトの移動は重要です。そうしないと、参照または const 参照として転送され、移動コンストラクターが呼び出されないためです。
コピーが必要ない場合。その場合、最善の方法は、ポインター ベクトル (または同じ目的に役立つ別の構造体) を使用することです。コピーが必要な場合。push_back() を直接使用します。他に選択肢はありません。