返回时为什么指针不能自动转换为unique_ptr?

ein*_*ica 15 c++ pointers explicit smart-pointers c++11

让我通过一个例子提出我的问题.

#include <memory>

std::unique_ptr<int> get_it() {
        auto p = new int;
        return p;
}

int main() {
        auto up ( get_it() );
        return 0;
}
Run Code Online (Sandbox Code Playgroud)

无法编译时出现以下错误:

a.cpp:5:9: error: could not convert ‘p’ from ‘int*’ to ‘std::unique_ptr<int>’
  return p;
         ^
Run Code Online (Sandbox Code Playgroud)

为什么没有从原始指针自动转换为唯一的指针?我应该做什么呢?

动机:我理解使用智能指针清除所有权应该是一种好习惯; 我从某个地方得到一个指针(我拥有),就像int*在这种情况下一样,我(想想我)想要它unique_ptr.


如果您正在考虑评论或添加您自己的答案,请在提案N4029中解决Herbert Sutter关于此问题的论点.

Ily*_*pov 16

答案是双重的.所有其他答案,包括OP的自我答案,只解决了其中的一半.

指针无法自动转换,因为:

  • unique_ptr声明了指针的构造函数explicit,因此编译器仅在显式上下文中考虑它.这样做是为了防止意外的危险转换,其中一个人unique_ptr可以劫持一个指针并在没有程序员知识的情况下删除它.一般而言,不仅仅是因为unique_ptr将所有单参数构造函数声明为explicit防止意外转换被认为是一种好习惯.
  • return语句被标准认为是隐式上下文,因此显式构造函数不适用.有一个正在进行的讨论,如果这个决定是正确的,体现在EWG问题114,包括链接到几个建议:建议书两个版本作出return明确由Herb萨特(N4029,N4074),以及两个"回应",称不这样做:Howard Hinnant和Ville Voutilainen的N4094FilipRoséen的N4131.经过多次讨论和民意调查后,该问题被关闭为NAD - 而不是缺陷.

目前,有几种解决方法:

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

要么

return std::unique_ptr<int>(p);
Run Code Online (Sandbox Code Playgroud)

在c ++ 14中,您也可以使用函数返回类型的自动推导:

auto get_it() {
    auto p = new int;
    return std::unique_ptr<int>(p);
}
Run Code Online (Sandbox Code Playgroud)

更新:为第二点添加了委员会问题的链接.


Sta*_*tas 7

因为unique_ptr来自裸指针的隐式构造将非常容易出错.

只需明确构造它:

std::unique_ptr<int> get_it() {
        auto p = new int;
        return std::unique_ptr<int>(p);
}
Run Code Online (Sandbox Code Playgroud)

  • 例如`foo(unique_ptr <int> p){}`在这种情况下将能够窃取传递的裸指针,并销毁该对象. (5认同)
  • 是的。裸指针的“unique_ptr”构造函数被定义为显式的。 (2认同)

Gin*_*lus 5

因为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
}
Run Code Online (Sandbox Code Playgroud)