【问题标题】:Why can I not instantiate std::vector<std::unique_ptr<int>> with {std::move(first), std::move(second)}? [duplicate]为什么我不能用 {std::move(first), std::move(second)} 实例化 std::vector<std::unique_ptr<int>>? [复制]
【发布时间】:2019-07-09 15:19:00
【问题描述】:

我有一个简单的函数,它应该构造一些对象并返回它们的向量,同时还转移所有权。我认为最好的方法是简单地返回对象的std::vector&lt;std::unique_ptr&lt;int&gt;&gt;(假设它们是int)。

当我尝试以下功能时:

std::vector<std::unique_ptr<int>> create_stuff() {
    auto first = std::make_unique<int>(1);
    auto second = std::make_unique<int>(2);
    return {std::move(first), std::move(second)};
}

我收到了一个非常长的编译错误,结尾是:

xmemory0(737): error C2280: 'std::unique_ptr<int,std::default_delete<_Ty>>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)':
attempting to reference a deleted function

我认为问题出在函数本身,但是以下解决方案效果很好:

std::vector<std::unique_ptr<int>> create_stuff() {
    auto first = std::make_unique<int>(1);
    auto second = std::make_unique<int>(2);
    std::vector<std::unique_ptr<int>> results;
    results.push_back(std::move(first));
    results.push_back(std::move(second));
    return results;
}

为什么第二个解决方案有效,但第一个无效?有没有一种解决方法可以让我在初始化列表中使用简短的语法?

【问题讨论】:

  • 因为初始值设定项列表被传递,然后您将其元素复制到向量中,所以您不会移动它们 AFAIK。
  • 而不是在你的例子中使用int(因为指向单个int 值的指针很少有意义),我建议你创建一个简单的类或结构来使用。它不必完全定义,因为这与问题无关,但至少它会更有意义。例如使用虚拟Foo 而不是int

标签: c++ unique-ptr initializer-list


【解决方案1】:

为什么第二种方案有效,第一种无效?

您使用的列表初始化语法调用接受std::initializer_list 的构造函数。 std::initializer_list 不可移动,std::initializer_list&lt;std::unique_ptr&lt;T&gt;&gt; 不可复制,因此无法调用构造函数。

在后面的例子中你使用了默认构造函数,所以没有问题。

是否有一种解决方法可以让我在初始化列表中使用简短的语法?

您可以列出初始化一个数组,并使用一对移动迭代器:

std::array arr{
    std::make_unique<int>(1),
    std::make_unique<int>(2),
};
return std::vector(
    std::make_move_iterator(std::begin(arr)),
    std::make_move_iterator(std::end(arr))
);

有一个proposal 可以使std::initializer_list 可移动,但它没有被采用(还没有被采用;谁知道未来会带来什么)。

【讨论】:

  • 谢谢,我接受了你的回答。该问题刚刚被标记为重复,并且链接的线程提供了相同的解决方法。感谢您提供该提案的链接!
【解决方案2】:

在我的平台上,相关代码是:

  vector(initializer_list<value_type> __l,
   const allocator_type& __a = allocator_type())
  : _Base(__a)
  {   _M_range_initialize(__l.begin(), __l.end(),
          random_access_iterator_tag());
  }

_M_range_initialize() 只是从迭代器复制,而不是从迭代器中移动。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-10-19
    • 2014-02-16
    • 2016-12-05
    • 2016-03-21
    • 2017-06-11
    • 1970-01-01
    相关资源
    最近更新 更多