观察std::unique_ptr及其nullptr_t构造函数

3

我正在尝试理解为什么unique_ptr有一个nullptr_t构造函数。

constexpr unique_ptr::unique_ptr( nullptr_t );

我曾经认为这是因为普通的单参数构造函数是显式的,因此会拒绝nullptr值:

explicit unique_ptr::unique_ptr( pointer p );

但是当我构建一个示例时,编译器能够正常工作:
namespace ThorsAnvil
{
    template<typename T>
    class SmartPointer
    {
        public:
            SmartPointer()      {}
            explicit SmartPointer(T*){}
    };
}


template<typename T>
using SP    = ThorsAnvil::SmartPointer<T>;
int main()
{

    SP<int>     data1;
    SP<int>     data2(new int);  // fine
    SP<int>     data3(nullptr);  // fine
}

以下是输出结果:
> g++ --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 6.0 (clang-600.0.56) (based on LLVM 3.5svn)
Target: x86_64-apple-darwin14.0.0
Thread model: posix
> g++ -Wall -Wextra -std=c++11 SP1.cpp

为什么std::unique_ptr需要额外的构造函数来接受nullptr_t参数?

我猜测,这是为了优化,因为它被声明为“constexpr”。 - Falmarri
nullptr_t 构造函数也是 explicit 的吗? - templatetypedef
@templatetypedef:不需要。只需要constexpr。 - Martin York
这将失败:SP<int> data; data = nullptr; - Bill Lynch
@CrappyExperienceBye,这可能就是你的答案-它允许直接分配nullptr。这是否足够证明了它的正当性? - templatetypedef
1个回答

6
SP<int>     data3(nullptr);  // fine

您正在使用直接初始化方式,这会导致编译器调用explicit构造函数。请尝试以下代码,您的程序将无法编译。
SP<int>     data4 = nullptr;

现在添加以下构造函数,上面的代码将编译通过。
SmartPointer(std::nullptr_t){}

因此,nullptr_t 构造函数使 unique_ptr 在您想将其初始化为 nullptr 时表现得像一个原始指针,但在其他情况下避免任何令人惊讶的所有权转移,例如实际分配原始指针。

SP<int> data5 = new int; 也失败了。 - Martin York
@CrappyExperienceBye 如果那个失败了,看看我刚刚添加的关于“令人惊讶”的所有权转移的最后一段。 - Praetorian
基本上,这是为了允许 SP<int> newData = nullptr;,并且有一个等效的赋值版本允许 newData = nullptr;。因此,我们可以轻松地重置 unique_ptr,但不会意外地分配它的指针。 - Martin York
@CrappyExperienceBye 是的,不仅仅是初始化/赋值。想想一个函数 void foo(unique_ptr<Type>) {...} 显然这个函数拥有参数的所有权。假设有人这样调用它 Type *t = new Type; foo(t); 让它编译通过并且函数默默地假定拥有所有权是不可取的行为。 - Praetorian
是的,我理解在使用 T* 时需要明确。我只是想知道为什么将 nullptr 特殊处理会很有用。 - Martin York
@CrappyExperienceBye 在这种情况下没有需要防范的地方,隐式转换是安全的。因此,这可能归结为允许您少打一些字并模仿原始指针,同时避免缺点。 - Praetorian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接