unique_ptr的问题

unique_ptr f()
{
unique_ptr p(new X);
return p;
}

这里返回p的话,会产生临时对象吗,会调用拷贝构造吗,可是unique_ptr是不允许调用拷贝构造的啊,为什么可以这么写?

请各位大大指教

阅读 3.8k
1 个回答

返回值优化

如果没有这个优化,这段代码就是错的,比如这样就没问题:

unique_ptr<int> f()
{
    unique_ptr<int> p(new int(10));
    return p;
}

有的编译器,比如GCC/Clang,可以用-fno-elide-constructors禁掉 “某些” NRVO,但不包括你写的这种(过于简单的)代码;MSVC不开优化选项也可以禁掉 “某些” NRVO,但也不包括这种情况。

如果你坚持要禁掉NRVO,可以这么干:

unique_ptr<int> *pp;
unique_ptr<int> f()
{
    unique_ptr<int> p(new int(10));
    *pp=&p;
    return p;
}

你会发现这样就编译不过了,因为在这段代码中,你给local的unique_ptr创建了一个alias,这样编译器就不能做这个优化,因为优化前后这个alias指向的对象是不一样的。
pp当然是个悬空的无效指针,但只要你不用它也不会出错,反正你只是要禁掉NRVO对不。

那么如果一个函数真要返回一个non-copyable object怎么办呢?
注意,NRVO的“N”指的是这个优化只针对Named return value,也就是说这种优化和没名字的临时变量无关。
由于匿名临时变量都是rvalue,所以在构造真正的返回结果对象时使用的是move-constructor而不是copy constructor,而unique_ptr当然是move-constructible,也就是说,make_unique只需要这么写:

template< class T, class... Args >
unique_ptr<T> make_unique( Args&&... args ) {
    return unique_ptr<T>(new T(std::forward<Args>(args)...));
}

这样就完全没问题了,无论有没有NRVO,反正它也不用。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题