C++ 将本地唯一\u ptr作为共享\u ptr返回
我习惯于在返回std::unique\u ptr时不使用std::move,因为这样做会禁止RVO。在这种情况下,我有一个本地std::unique\u ptr,但返回类型是std::shared\u ptr。 下面是代码示例:C++ 将本地唯一\u ptr作为共享\u ptr返回,c++,gcc,clang,language-lawyer,c++14,C++,Gcc,Clang,Language Lawyer,C++14,我习惯于在返回std::unique\u ptr时不使用std::move,因为这样做会禁止RVO。在这种情况下,我有一个本地std::unique\u ptr,但返回类型是std::shared\u ptr。 下面是代码示例: shared_ptr<int> getInt1() { auto i = make_unique<int>(); *i = 1; return i; } shared_ptr<int> getInt2()
shared_ptr<int> getInt1() {
auto i = make_unique<int>();
*i = 1;
return i;
}
shared_ptr<int> getInt2() {
return make_unique<int>(2);
}
unique_ptr<int> getInt3() {
auto ptr = make_unique<int>(2);
return ptr;
}
int main() {
cout << *getInt1() << endl << *getInt2() << *getInt3() << endl;
return 0;
}
科里鲁的两个案例如下:
两个编译器都接受第三种情况
哪一个是错的?谢谢。std::unique\u ptr只有在为右值时才能用于构造std::shared\u ptr。请参见以下内容的构造函数声明:
顺便说一句:我用它编译代码也失败了
source_file.cpp:14:12: error: cannot bind ‘std::unique_ptr<int, std::default_delete<int> >’
lvalue to ‘std::unique_ptr<int, std::default_delete<int> >&&’
return i;
^
<正确答案取决于你所谈论的C++标准。< /P> 如果我们谈论的是C++11,那么clang是正确的,需要显式移动。如果我们谈论的是C++14,那么gcc是正确的,不需要显式移动 C++11在N3290/[class.copy]/p32中说: 当满足或将满足省略复制操作的条件时 met save,因为源对象是函数参数, 要复制的对象由左值重载指定 首先执行为副本选择构造函数的解析 好像对象是由右值指定的。If重载解析 失败 这要求仅当返回表达式的类型与函数返回类型相同时,才能获得隐式移动 但是改变了这一点,这个缺陷报告在C++11之后被接受,并且在C++14之前被及时接受。该段现改为: 当满足省略复制/移动操作的条件时,但是 不适用于异常声明,并且要复制的对象是 由左值指定,或者在返回语句中的表达式 是一个可能带括号的id表达式,它使用 正文中声明的自动存储持续时间或 最内层封闭函数的参数声明子句或 lambda表达式,用于选择构造函数的重载解析 首先执行复制,就好像对象是由 右值。如果第一次重载解析失败或未执行 这种修改基本上允许返回表达式类型转换为函数返回类型,并且仍然可以进行隐式移动 这是否意味着代码需要基于uucplusplus值的if/else 有人可以这样做,但我不会费心。如果我的目标是C++14,我只会:
return i;
如果代码意外地在C++11编译器下运行,则会在编译时通知您该错误,并且很容易修复:
return std::move(i);
如果您只是针对C++11,请使用移动
如果您想同时针对C++11和C++14及更高版本,请使用move。无偿使用move的缺点是可以抑制RVO返回值优化。但是,在这种情况下,RVO甚至是不合法的,因为它将返回语句转换为函数的返回类型。因此,这种无缘无故的举动不会造成任何伤害
有一次你可能会倾向于一个毫无意义的移动,即使目标是C++14,如果没有它,事情仍然在C++11中编译,并调用一个昂贵的副本转换,而不是移动转换。在这种情况下,意外地在C++11下编译会引入一个无声的性能错误。而且,在C++14下编译时,这种无缘无故的移动仍然没有有害影响。我怀疑,当我们了解您需要它的原因时,我们将能够给出更好的答案。目前,可以通过调用make_shared而不是make_unique来解决这个问题。我想这不可能是有原因的,这将有助于理解这个原因。@Elliott:什么问题可以解决?他不是问如何解决任何问题,而是问他拥有的代码是否符合标准。您好,您能否更改您的答案,以指定移动仅适用于c++11?如果您仅使用c++11,我建议您在返回之前创建正确的类型,而不是使用return std::move。。。在你的代码中。因为编译器可能只是执行NRVO,而不是移动几次。
source_file.cpp:14:12: error: cannot bind ‘std::unique_ptr<int, std::default_delete<int> >’
lvalue to ‘std::unique_ptr<int, std::default_delete<int> >&&’
return i;
^
return i;
return std::move(i);