我可以通过元素的完美转发来列表初始化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;
}

我真的需要使用emplace_back来尽可能高效地初始化std :: vector吗?

// 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的构造函数令人困惑,恕我直言,如果我是你,我真的不必绝对不必进入。另外,如果您事先知道矢量的内容(似乎是这种情况),请考虑使用std::array
einpoklum

1
operator=破坏源的An 非常不寻常,可能会导致意外问题。
alain

1
init_emplace_vector可以通过vec.reserve(sizeof...(Args))
Indiana Kernick

1
@alain operator=不会破坏源。这是复制交换的习惯用法。
侦听

Answers:


11

我可以聚合初始化std :: vector ...

编号std::vector不是聚合,因此无法进行聚合初始化。

在这种情况下,您可能要用列表初始化来代替:

我可以完美地转发元素的[列表初始化] std :: vector吗?

不会。列表初始化使用std::initializer_list构造函数并std::initializer_list复制其参数。

init_emplace_vector似乎是一个不错的解决方案,尽管可以通过在添加元素之前保留内存来改善它。


1
感谢您纠正我。已编辑。有储备的好点。
reconn
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.