为什么unique_ptr <T>(T*)是显式的?

fre*_*low 29 c++ pointers type-conversion unique-ptr c++11

以下函数无法编译:

std::unique_ptr<int> foo()
{
    int* answer = new int(42);
    return answer;
}

std::unique_ptr<int> bar()
{
    return new int(42);
}
Run Code Online (Sandbox Code Playgroud)

我觉得这有点不方便.std::unique_ptr<T>(T*)明确的理由是什么?

Dav*_*eas 28

您不希望托管指针隐式获取原始指针的所有权,因为这可能最终导致未定义的行为.考虑一个函数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 );...

获取所有权是一项非常重要的操作,最好明确说明:程序员(而不是编译器)知道是否应该通过智能指针管理资源.

  • +1,esp表示"获得所有权是一项非常重要的操作,因此最好将其明确化." (4认同)

Naw*_*waz 19

简短回答:

明确的构造使得它很难写出危险的代码.换句话说,隐式构造函数可以帮助您更轻松地编写危险代码.

答案很长:

如果构造函数是隐式的,那么您可以轻松地编写这样的代码:

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. 
Run Code Online (Sandbox Code Playgroud)

现在看危险的部分:

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!
Run Code Online (Sandbox Code Playgroud)

请阅读评论.它解释了上面代码片段的每个部分.

当调用f()与原始指针,程序员可能没有意识到,参数类型的f()std::unique_ptr,这将带指针的所有权,将delete它时,它超出范围.另一方面,程序员可能会使用它,delete甚至没有意识到它已被删除!这一切都是因为从原始指针隐式转换而发生的std::unique_ptr.

请注意,std::shared_ptr由于explicit同样的原因,它具有构造函数.