如果我通过我的GCC 4.7快照传递以下代码,它会尝试将 unique_ptr
复制到向量中 .
#include <vector>
#include <memory>
int main() {
using move_only = std::unique_ptr<int>;
std::vector<move_only> v { move_only(), move_only(), move_only() };
}
显然这不起作用,因为 std::unique_ptr
不可复制:
错误:使用已删除的函数'std :: unique_ptr <_Tp,_Dp> :: unique_ptr(const std :: unique_ptr <_Tp,_Dp>&)[with _Tp = int; _Dp = std :: default_delete; std :: unique_ptr <_Tp,_Dp> = std :: unique_ptr]'
GCC是否正确尝试从初始化列表中复制指针?
5 回答
18.9中
<initializer_list>
的概要使得初始化列表的元素总是通过const-reference传递时相当清楚 . 不幸的是,似乎没有任何方法在语言的当前版本中使用初始化列表元素中的move-semantic .具体来说,我们有:
Edit: 由于@Johannes没有't seem to want to post the best solution as an answer, I' ll就这么做 .
std::make_move_iterator
返回的迭代器将在解除引用时移动指向的元素 .Original answer: 我们将在这里使用一个小助手:
可悲的是,这里的直接代码不起作用:
由于标准,无论出于何种原因,都没有定义像这样的转换复制构造函数:
由brace-init-list(
{...}
)创建的initializer_list<rref_wrapper<move_only>>
将不会转换为vector<move_only>
所采用的initializer_list<move_only>
. 所以我们需要在这里进行两步初始化:正如在其他答案中所提到的,
std::initializer_list
的行为是按值保存对象而不允许向外移动,因此这是不可能的 . 这是一种可能的解决方法,使用函数调用,其中初始值设定项作为可变参数给出:不幸的是
multi_emplace(foos, {});
失败了,因为它无法推断出{}
的类型,所以对于默认构造的对象,你必须重复类名 . (或使用vector::resize
)使用Johannes Schaub的
std::make_move_iterator()
与std::experimental::make_array()
的技巧,您可以使用辅助函数:在Coliru上看到它 .
也许有人可以利用
std::make_array()
的诡计让make_vector()
直接做它的事情,但我没有看到(更准确地说,我尝试了我认为应该工作,失败和继续前进的事情) . 在任何情况下,编译器都应该能够将数组内联到矢量转换,就像Clang在GodBolt上使用O2一样 .正如已经指出的那样,无法使用初始化列表初始化仅移动类型的向量 . @Johannes最初提出的解决方案工作正常,但我还有另一个想法......如果我们不创建临时数组然后将元素从那里移动到向量中,但是使用placement
new
初始化此数组已经代替向量的内存块?这是我使用参数包初始化
unique_ptr
的向量的函数: