web-dev-qa-db-ja.com

std :: vectorはPush_backでオブジェクトをコピーしていますか?

Valgrindで多くの調査を行った結果、std :: vectorはPush_backしたいオブジェクトのコピーを作成すると結論付けました。

それは本当ですか?ベクトルは、コピーなしではオブジェクトの参照またはポインターを保持できませんか?!

ありがとう

152
benlaug

はい、std::vector<T>::Push_back()は引数のコピーを作成し、ベクターに保存します。ベクターへのオブジェクトへのポインターを保存する場合は、std::vector<whatever*>の代わりにstd::vector<whatever>を作成します。

ただし、ベクトルが参照を保持している間、ポインターによって参照されるオブジェクトが有効なままであることを確認する必要があります(RAIIイディオムを利用するスマートポインターが問題を解決します)。

167

はい、std::vectorはコピーを保存します。 vectorは、オブジェクトの予想寿命をどのように知る必要がありますか?

オブジェクトの所有権を転送または共有する場合は、ポインターを使用します。おそらく、shared_ptrのようなスマートポインター( Boostにあります またはTR1)リソース管理を容易にします。

33
Georg Fritzsche

C++ 11以降、すべての標準コンテナ(std::vectorstd::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.
24
Karl Nicoll

std :: vectorは、ベクターに保存されているもののコピーを常に作成します。

ポインターのベクトルを保持している場合、ポインターのコピーが作成されますが、ポインターが指しているインスタンスは作成されません。大きなオブジェクトを扱う場合は、常にポインターのベクトルを使用できます(おそらくそうすべきです)。多くの場合、適切なタイプのスマートポインターのベクトルを使用すると、オブジェクトの有効期間とメモリ管理の処理が難しくなる可能性があるため、安全性の目的に適しています。

15
Reed Copsey

Std :: vectorは、プッシュバックするもののコピーを作成するだけでなく、コレクションの定義により、コピーが行われ、ベクター内で正しいコピーセマンティクスを持たないオブジェクトを使用できないことが示されます。したがって、たとえば、ベクトルでauto_ptrを使用しません。

3
Liz Albin

C++ 11に関連するのは、emplaceファミリーのメンバー関数です。これにより、オブジェクトをコンテナーに移動することにより、オブジェクトの所有権を転送できます。

使用法のイディオムは次のようになります

std::vector<Object> objs;

Object l_value_obj { /* initialize */ };
// use object here...

objs.emplace_back(std::move(l_value_obj));

左辺値オブジェクトの移動は重要です。そうしないと、参照またはconst参照として転送され、移動コンストラクターは呼び出されません。

2
LemonPi

なぜこれを見つけるのに多くのvalgrind調査が必要でしたか!単純なコードを使って自分自身に証明してください。

std::vector<std::string> vec;

{
      std::string obj("hello world");
      vec.Push_pack(obj);
}

std::cout << vec[0] << std::endl;  

「hello world」が出力される場合、オブジェクトはコピーされている必要があります

0
NexusSquared

コピーしたくない場合;最適な方法は、ポインターベクトル(または同じ目標に役立つ別の構造体)を使用することです。コピーが必要な場合;直接Push_back()を使用します。他の選択肢はありません。

0
rahmivolkan