将本地unique_ptr作为shared_ptr返回
Returning local unique_ptr as a shared_ptr
我习惯于在返回std::unique_ptr
时不使用std::move
,因为这样做会禁止RVO。在这种情况下,我有一个本地std::unique_ptr
,但返回类型是std::shared_ptr
。以下是代码示例:
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;
}
GCC接受这两种情况,但Clang拒绝getInt1()
。出现以下错误:
main.cpp:10:13: error: no viable conversion from 'std::unique_ptr<int, std::default_delete<int> >' to 'shared_ptr<int>'
return i;
^
以下是coliru上的两种情况:GCC、Clang
两个编译器都接受第三种情况。
哪一个错了?谢谢
正确答案取决于您所说的C++标准。
如果我们谈论的是C++11,clang是正确的(需要明确的移动(。如果我们谈论的是C++14,那么gcc是正确的(不需要显式移动(。
C++11在N3290/[class.copy]/p32:中说
当满足或将满足省略复制操作的标准时除了源对象是函数参数这一事实之外,并且要复制的对象由左值重载指定首先执行为副本选择构造函数的解析就好像对象是由右值指定的一样。如果过载解决方案失败。。。
这要求只有当返回表达式的类型与函数返回类型相同时,才能获得隐式移动。
但CWG 1579改变了这一点,该缺陷报告在C++11之后被接受,并在C++14及时被接受。同一段现在改为:
当满足省略复制/移动操作的标准时,但是不适用于异常声明,并且要复制的对象是由左值指定,或者当
return
语句中的表达式是一个(可能带括号(id表达式,它用正文中声明的自动存储持续时间或最里面的封闭函数的参数声明子句或lambda表达式,用于选择构造函数的重载解析首先执行复制,就好像对象是由右值。如果第一次过载解决失败或未执行。。。
这种修改基本上允许返回表达式类型可转换为函数返回类型,并且仍然有资格进行隐式移动。
这是否意味着代码需要基于__cplusplus
的值的#if
/#else
一个人可以这么做,但我不会麻烦的。如果我的目标是C++14,我只会:
return i;
如果代码意外地在C++11编译器下运行,您将在编译时收到错误通知,修复起来很简单:
return std::move(i);
如果您只是针对C++11,请使用move
。
如果要同时针对C++11和C++14(及更高版本(,请使用move
。免费使用move
的缺点是可以禁止RVO(返回值优化(。然而,在这种情况下,RVO甚至是不合法的(因为从return
语句转换为函数的返回类型(。因此,免费的move
不会伤害任何东西。
有一次,即使在以C++14为目标的情况下,你也可能倾向于使用免费的move
,如果没有它,事情仍然在C++11中编译,并调用昂贵的复制转换,而不是移动转换。在这种情况下,意外地在C++11下编译会引入一个静默的性能错误。并且当在C++14下编译时,免费的move
仍然没有任何不利影响。
std::unique_ptr
只能在它是右值时用于构造std::shared_ptr
。参见std::shared_ptr
:的构造函数声明
template< class Y, class Deleter >
shared_ptr( std::unique_ptr<Y,Deleter>&& r );
因此,您需要使用std::move
使第一个案例起作用,否则它应该会失败。
return std::move(i);
BTW:我用gcc 4.9.3编译了代码,它也失败了。
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;
^
- CLANG 编译器 说:变量"PTR"可能未初始化
- 在以唯一ptr为值的C++映射中,动态内存何时会被销毁
- 将 ptr 传递给 ptr 到 A 作为参数传递给 A 的函数是不好的做法吗?
- 为共享 ptr 向量实现复制 c'tor?
- 字符和整数中 **(ptr+1) 的值差异
- C++:在不中断共享的情况下通过引用传递共享 PTR?
- 如何将派生类从基 ptr 分配给 nlohmann::json
- 引用 std::shared:ptr 以避免引用计数
- 为什么我不能在不进行任何转换的情况下将浮点数放入任何类型的 ptr 中?
- 在调用函数时,ptr** 和 ptr*& 之间是否有区别,或者首选C++?
- 另一种类型的智能ptr,比如具有弱refs的unique_ptr
- 尝试打印出 *ptr++ 的值,以了解它是如何工作的
- 如何控制共享 ptr 引用计数?
- dopen():不以 root 身份运行时"failed to map segment from shared object"
- C++中的指针否定 (!ptr == NULL)
- 从const ptr*转换为ptr*时出现问题
- 无法使用 libtool 将 -shared 参数传递给 g++
- boost::shared_ptr和std::shared-ptr的同居
- 我可以用std::shared_ptr而不是boost::shared-ptr构建boost库吗
- shared-ptr-C++shared_ptr与unique_ptr用于资源管理