请考虑以下程序:
#include <memory>
std::unique_ptr<int> get_it() {
auto p = new int;
return p;
}
int main() {
auto up ( get_it() );
return 0;
}
这无法编译,并显示以下错误:
a.cpp:5:9: error: could not convert ‘p’ from ‘int*’ to ‘std::unique_ptr<int>’
return p;
^
为什么这里没有从原始指针到唯一指针的自动转换?我应该怎么做呢?
动机:我知道使用智能指针来明确所有权应该是很好的做法;在这种情况下,我从某个地方获得一个指针(我拥有),作为int*
,我(认为我)想要它在unique_ptr
.
如果您正在考虑评论或添加自己的答案,请在提案 N4029 中解决 Herbert Sutter 的论点。
答案是双重的。所有其他答案,包括OP的自我回答,都只解决了其中的一半。
指针无法自动转换,因为:
-
unique_ptr
的构造函数从指针被声明为explicit
,因此编译器只在显式上下文中考虑。这样做是为了防止意外的危险转换,unique_ptr
可以在程序员不知情的情况下劫持指针并将其删除。一般来说,不仅对于unique_ptr
,将所有单参数构造函数声明为explicit
以防止意外转换被认为是一种很好的做法。 - return 语句被标准视为隐式上下文,因此显式构造函数不适用。如果这个决定是正确的,正在进行讨论,反映在EWG第114期中,包括几个提案的链接:Herb Sutter(N4029,N4074)明确
return
的两个提案版本,以及两个"回应",认为不要这样做:Howard Hinnant和Ville Voutilainen的N4094和Filip Roséen的N4131。经过几次讨论和民意调查,该问题被关闭为NAD - 不是缺陷。
目前,有几种解决方法:
return std::unique_ptr<int>{p};
或
return std::unique_ptr<int>(p);
在 c++14 中,您也可以使用函数返回类型的自动推导:
auto get_it() {
auto p = new int;
return std::unique_ptr<int>(p);
}
更新:为第二点添加了指向委员会问题的链接。
因为从裸指针隐式构造unique_ptr
非常容易出错。
只需显式构造它:
std::unique_ptr<int> get_it() {
auto p = new int;
return std::unique_ptr<int>(p);
}
因为std::unique_ptr
拥有指针的所有权,而且您绝对不希望意外地获得原始指针delete
d。
如果可能的话,那么:
void give_me_pointer(std::unique_ptr<int>) { /* whatever */ }
int main() {
int *my_int = new int;
give_me_pointer(my_int);
// my_int is dangling pointer
}
因为转换或强制转换需要适当的强制转换运算符(在源类型上)或构造函数(在目标类型上)。在这种情况下,它必须是以下 unique_ptr
构造函数:
explicit unique_ptr( pointer p );
其中有显式关键字。 您的get_it()
尝试隐式转换,这explicit
阻止。相反,您必须按照 @Stas 和 @VincentSavard 的建议显式构造unique_ptr
:
std::unique_ptr<int> get_it() {
auto p = new int;
return std::unique_ptr<int>(p);
}
甚至,如果我们只想说unique_ptr
一次......
auto get_it() {
auto p = new int;
return std::unique_ptr<int>(p);
}
因为它很危险。
使用 C++14 中的std::make_unique()
:
std::unique_ptr<int> get_it()
{
auto p = std::make_unique<int>();
return p;
}