关于 std::unique_ptr 的思考

关于 std::unique_ptr 的思考

std::unique_ptr 表示独占所有权的智能指针,正常情况下,此智能指针管理内存的获取与释放,而普通指针仅负责使用内存;

禁止拷贝

由于 std::unique_ptr 表示独占的含义,所以其是不支持拷贝的,在C++标准库中,unique_ptr 禁止拷贝的实现如下 [ 代码片段来自 MinGW5.3.0 中的 unique_ptr.h ]:

template <typename _Tp, typename _Dp = default_delete<_Tp>>
class unique_ptr {
public:
    // ...
    // Disable copy from lvalue.
    unique_ptr(const unique_ptr&) = delete;
    unique_ptr& operator=(const unique_ptr&) = delete;
    // ...
};

由代码可知,禁止拷贝的实现中采用了C++11的 delete 关键字;而在C++11之前,若要实现禁止拷贝的功能,传统方法是将拷贝构造与赋值运算符私有化,这样是非常不直观的,示例代码如下:

// C++98/03风格的禁止拷贝实现方式
class Demo {
public:
    Demo();
    // ...
private:
    Demo(const Demo& rhs);
    Demo& operator=(const Demo& rhs);
    // ...
}

函数返回

在C++标准中,std::unique_ptr 是支持函数返回的,最为典型的就是 std::make_unique,其实现代码如下 [ 代码片段来自 MinGW5.3.0 中的 unique_ptr.h ]:

/// std::make_unique for single objects
template<typename _Tp, typename... _Args>
inline typename _MakeUniq<_Tp>::__single_object
make_unique(_Args&&... __args)
{
    return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); 
}

既然 std::unique_ptr 不支持拷贝,那么为什么其可以进行函数返回呢?这似乎与不支持拷贝是矛盾的;

我们知道,在函数返回中,返回值优化RVO(其在C++17中进入标准)可以让对象直接在函数调用处生成, 而不产生多余的临时对象,从而绕过拷贝/移动构造操作;

因此,std::unique_ptr 的能够函数返回的重要机制是返回值优化RVO绕过了拷贝/移动构造,使其能够函数返回;

开发启示

如上所述,C++标准库在实现中大量应用了C++11/14/17等现代特性,如 =delete,RVO,等;

所以,在开发实践中,我们亦应编写现代C++风格的代码,与时俱进,才能让程序更优雅,更具维护性;


本文作者: 王同学