要素を完全に転送してstd :: vectorをリスト初期化できますか?


14

std :: vectorの集約 リストの初期化は移動がより適切な場合にコピーの初期化を実行することに気付きました。同時に、複数のemplace_backsが必要な処理を実行します。

テンプレート関数を書くというこの不完全な解決策しか思いつかなかったinit_emplace_vector。ただし、明示的でない単一値コンストラクターにのみ最適です。

template <typename T, typename... Args>
std::vector<T> init_emplace_vector(Args&&... args)
{
  std::vector<T> vec;
  vec.reserve(sizeof...(Args));  // by suggestion from user: eerorika
  (vec.emplace_back(std::forward<Args>(args)), ...);  // C++17
  return vec;
}

質問

std :: vectorをできるだけ効率的に初期化するために、本当にemplace_backを使用する必要がありますか?

// an integer passed to large is actually the size of the resource
std::vector<large> v_init {
  1000,  // instance of class "large" is copied
  1001,  // copied
  1002,  // copied
};

std::vector<large> v_emplaced;
v_emplaced.emplace_back(1000);  // moved
v_emplaced.emplace_back(1001);  // moved
v_emplaced.emplace_back(1002);  // moved

std::vector<large> v_init_emplace = init_emplace_vector<large>(
  1000,   // moved
  1001,   // moved
  1002    // moved
);

出力

クラスlargeはコピー/移動(以下の実装)に関する情報を生成するので、私のプログラムの出力は次のとおりです。

- initializer
large copy
large copy
large copy
- emplace_back
large move
large move
large move
- init_emplace_vector
large move
large move
large move

大規模クラスの実装

私の実装largeは、コピー/移動を警告する大きなリソースを保持する、単にコピー/移動可能なタイプです。

struct large
{
  large(std::size_t size) : size(size), data(new int[size]) {}

  large(const large& rhs) : size(rhs.size), data(new int[rhs.size])
  {
    std::copy(rhs.data, rhs.data + rhs.size, data);
    std::puts("large copy");
  }

  large(large&& rhs) noexcept : size(rhs.size), data(rhs.data)
  {
    rhs.size = 0;
    rhs.data = nullptr;
    std::puts("large move");
  }

  large& operator=(large rhs) noexcept
  {
    std::swap(*this, rhs);
    return *this;
  }

  ~large() { delete[] data; }

  int* data;
  std::size_t size;
};

編集する

予約を使用すると、コピーや移動はありません。large::large(std::size_t)コンストラクタのみが呼び出されます。本当の場所。


1
これは集約初期化ではなく、を受け取るコンストラクタを呼び出していますstd::initializer_list
スーパー

std :: vectorのコンストラクターは混乱を招く混乱したIMHOであり、もし私があなただったら、絶対にやらなくてはならないのであれば、その中に入るのは本当に避けたいでしょう。さらに、ベクターのコンテンツを事前に知っている場合(そうであるように思われます)-を検討してくださいstd::array
アインポクルム

1
operator=ソースを破壊するには、非常に異例のことだと予期しない問題が発生する可能性があります。
アラン・

1
init_emplace_vector改善のvec.reserve(sizeof...(Args))
余地

1
@alain operator=はソースを破壊しません。コピースワップイディオムです。
1

回答:


11

std :: vectorを集約初期化できますか?

No. std::vectorはアグリゲートではないため、アグリゲートで初期化することはできません。

代わりにリストの初期化を意味するかもしれません。その場合、

要素を完全に転送してstd :: vector を[list-initialise]できますか?

いいえ。リストの初期化ではstd::initializer_listコンストラクタを使用し、std::initializer_listその引数をコピーします。

init_emplace_vector要素を配置する前にメモリを予約することで改善できるかもしれませんが、あなたはまともな解決策のようです。


1
私を訂正してくれてありがとう。編集。予備との良い点。
1
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.