142


53

std :: vectorはpush_backでオブジェクトをコピーしていますか?
valgrindで多くの調査を行った結果、std

vectorはpush_backしたいオブジェクトのコピーを作成すると結論付けました。

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

ありがとう

8 Answer


154


はい、 `std

vector :: push_back()は引数のコピーを作成してベクターに保存します。 ベクターのオブジェクトへのポインターを保存したい場合は、 `std :: vector`の代わりに std :: vector`を作成します。

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


33


はい、 `std

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

オブジェクトの所有権を転送または共有する場合は、ポインタを使用します。「shared_ptr」などのスマートポインタ(http://www.boost.org/doc/libs/1_42_0/libs/smart_ptr/smart_ptr.htm[Boost]にあります)または_TR1_)リソース管理を容易にします。


23


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 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> myPtrList;

// #5a unique_ptr can only ever be moved.
auto pFoo = std::make_unique(1, "foo");
myPtrList.push_back(std::move(pFoo));

// #5b unique_ptr can only ever be moved.
myPtrList.push_back(std::make_unique(1, "foo"));
  • `std :: shared_ptr`の例*

std::vector> 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(1, "foo");
objectPtrList2.push_back(pFooShared);
// Pointer to object stored in the vector, but pFooShared is still valid.


15


std

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

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


3


std

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


2


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

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

std::vector objs;

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

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

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


0


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


0


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

std::vector vec;

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

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

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