【问题标题】:How to emplace elements while constructing std::vector?如何在构造 std::vector 时放置元素?
【发布时间】:2018-03-23 00:18:44
【问题描述】:

我想构造一个std::vector,其中的一些元素具有由某些特定构造函数而不是默认构造函数构造的这些元素。换句话说,我想在构建向量时放置元素。我该怎么做?

考虑this

struct Item
{
    Item(double) {}
    Item(const Item&) = delete;
    Item(Item&&) = delete;
};
std::vector<Item> vv(10, 3.14); // Fails! Tries to copy while I want to emplace.

【问题讨论】:

  • 也许向量对你来说是错误的容器,也许你应该改用std::array?或者您可以详细说明您遇到的实际 问题? 为什么您想出了需要帮助的解决方案?这是一个非常典型的XY problem 类型的问题。
  • @Someprogrammerdude 实际上,不是std::vector 也不是std::array,而是内置的动态数组是最适合目的的数据结构(动态但固定大小,没有修改)。但是内置的动态数组不支持这个 emplace-while-constructing 功能。
  • 好吧,考虑到标准 C++ 中不存在“动态数组”(我假设您的意思是 variable-length arrays?),这也不是一个选择。或者你的意思是new[]?也许您的原始问题可以通过其他方式解决?
  • @Someprogrammerdude 我的意思是new[]原始问题是有一组预定义的(但在运行时知道,而不是编译时知道)数量的std::threads,这些std::threads 使用相同的lambda 进行初始化。因此禁止复制,最好避免移动(理想情况下我不应该移动)。

标签: c++11 vector constructor emplace


【解决方案1】:

您的Item 类不支持复制和移动。这将阻止对std::vector 的大多数操作进行编译,包括std::vector::reservestd::vector::resize。如果你真的有这样的课程,你可能想要一个std::vector&lt;std::aligned_storage_t&lt;sizeof(Item), alignof(Item)&gt;&gt;

如果您可以向Item 添加移动构造函数,则可以创建辅助函数(因为您使用的构造函数重载是根据复制定义的)。请注意,以下版本仅适用于一元构造函数。

template <typename T, typename Arg>
auto make_vector(std::size_t n, Arg&& arg)
{
    std::vector<T> result;
    result.reserve(n);

    for(std::size_t i = 0; i < n; ++i)
        result.emplace_back(arg);

    return result;
}

用法:

auto vec = make_vector<Item>(10, 3.14);

【讨论】:

  • 非用逗号折叠的表达式很棒,把它放回去!它甚至不在编辑历史记录中:/
  • @BartekBanachewicz:它做错了:P
  • 哦,好吧。它让我意识到逗号实际上是一个运算符:D
  • @VittorioRomeo 我不需要对std::vector 进行编译(如问题评论中所述)。事实上,我只需要构造函数(我想要的那个)和析构函数。您的建议实际上是我现在代码中的解决方法։)缺点是:默认构造函数+保留(可能导致重新分配)而不是我想要的构造函数 .如果有一个 std::vector 的构造函数只是保留,那么解决方法将没有缺点(除了更多的代码行)。
  • 我认为 chris draw 的回答是正确的。 Vector 允许从迭代器进行构造,并放置元素。
【解决方案2】:

您可以使用带有两个迭代器的向量构造函数。例如,您可以使用来自 vector&lt;double&gt; 的迭代器。

std::vector<double> init(10, 3.14);
std::vector<Item> vv(init.begin(), init.end());

Live demo.

或者您可以编写自己的自定义迭代器类来进行初始化:

struct ItemInitializer {
  int index;
  double value;

  using value_type = double;
  using difference_type = int;  
  using pointer = const double*;
  using reference = const double&;
  using iterator_category = std::forward_iterator_tag;

  ItemInitializer() : index(0), value(0.0) {}
  ItemInitializer(int index, double v = 0.0) : index(index), value(v) {}

  bool             operator!=(const ItemInitializer& other) const { return other.index != index; }
  ItemInitializer& operator++() { index++; return *this; }
  ItemInitializer  operator++(int) { ItemInitializer ret(index, value); index++; return ret; }
  const double&    operator*() const { return value; }  
  const double*    operator->() const { return &value; } 
};

std::vector<Item> vv(ItemInitializer{0, 3.14}, ItemInitializer{10});

Live demo.

【讨论】:

    猜你喜欢
    • 2019-10-19
    • 1970-01-01
    • 2015-08-01
    • 2010-11-28
    • 1970-01-01
    • 2012-07-10
    • 1970-01-01
    • 2011-12-27
    • 2012-07-28
    相关资源
    最近更新 更多