以下函数无法编译:
std::unique_ptr<int> foo()
{
int* answer = new int(42);
return answer;
}
std::unique_ptr<int> bar()
{
return new int(42);
}
我觉得这有点不方便。std::unique_ptr<T>(T*)
明确的理由是什么?
以下函数无法编译:
std::unique_ptr<int> foo()
{
int* answer = new int(42);
return answer;
}
std::unique_ptr<int> bar()
{
return new int(42);
}
我觉得这有点不方便。std::unique_ptr<T>(T*)
明确的理由是什么?
您不希望托管指针隐式获取原始指针的所有权,因为这可能会导致未定义的行为。考虑一个函数void f( int * );
和一个调用int * p = new int(5); f(p); delete p;
。现在假设有人重构f
以获取托管指针(任何类型)并且允许隐式转换:void f( std::unique_ptr<int> p );
如果允许隐式转换,您的代码将编译但会导致未定义的行为。
以同样的方式考虑指针甚至可能不是动态分配的:int x = 5; f( &x );
...
获取所有权是一项非常重要的操作,最好明确说明:程序员(而不是编译器)知道是否应该通过智能指针管理资源。
简短的回答:
显式构造函数使得编写危险代码变得困难。换句话说,隐式构造函数可以帮助您更轻松地编写危险代码。
长答案:
如果构造函数是隐式的,那么您可以轻松编写这样的代码:
void f(std::unique_ptr<int> param)
{
//code
} //param will be destructed here, i.e when it goes out of scope
//the pointer which it manages will be destructed as well.
现在看看危险的部分:
int *ptr = new int;
f(ptr);
//note that calling f is allowed if it is allowed:
//std::unique_ptr<int> test = new int;
//it is as if ptr is assigned to the parameter:
//std::unique_ptr<int> test = ptr;
//DANGER
*ptr = 10; //undefined behavior because ptr has been deleted by the unique_ptr!
请阅读评论。它解释了上面代码片段的每个部分。
当使用原始指针调用f()
时,程序员可能没有意识到参数类型f()
将std::unique_ptr
获取指针的所有权,并且delete
在超出范围时将获取。另一方面,程序员可能会使用它,而delete
它甚至没有意识到它已经被删除了!这一切都是因为从原始指针隐式转换到std::unique_ptr
.
请注意,出于同样的原因,std::shared_ptr
具有构造函数。explicit