STL中的智能指针(Smart Pointer)及其源码剖析: std::unique_ptr

时间:2022-12-06 07:58:59


STL中的智能指针(Smart Pointer)及其源码剖析: std::unique_ptr

  • 和 ​​std::auto_ptr​​​一样,​​std::unique_ptr​​​也是一种智能指针,它也是通过指针的方式来管理对象资源,并且在 ​​unique_ptr​​ 的生命期结束后释放该资源。
  • ​unique_ptr​​​ 持有对对象的独有权 —— 两个 ​​unique_ptr​​ 不能指向一个对象,不能进行复制操作只能进行移动操作。
  • 当发生下列情况是, ​​unique_ptr​​​ 会所管理的指针使用其关联的 ​​deleter​​​:
    a. 负责管理的 ​​​unique_ptr​​​ 对象被销毁时;
    b. 负责管理的 ​​​unique_ptr​​​ 对象通过 ​​operator=​​​ 或 ​​reset​​ 函数赋值给另一个指针。

一. unique_ptr 的使用

1. unique_ptr 的声明

// since C++11

template<class T, class Deleter = std::default_delete<T>> (1)
class unique_ptr;

template<class T, class Deleter> (2)
class unique_ptr<T[], Deleter>;

(1) 管理单个对象泛化的 ​​unique_ptr​​​ 模板的声明。
(2) 对 (1) 版本, 针对对象数组进行特化后的版本的声明。

2. ​​unique_ptr 的构造函数​

  • ​unique_ptr<T>​​ 的构造函数。
constexpr unique_ptr();                                        (1)
constexpr unique_ptr(nullptr_t);

explicit unique_ptr(pointer p); (2)

unique_ptr(pointer p, (3)
typename conditional<is_reference<Deleter>::value,
Deleter, const Deleter&>::type d);

unique_ptr(pointer p, (4)
typename remove_reference<Deleter>::type&& d);

unique_ptr(unique_ptr&& u); (5)

template<class U, class E> (6)
unique_ptr(unique_ptr<U, E>&& u);

template<class U> (7)
unique_ptr(auto_ptr<U>&& u);

(1) 构造一个没有管理任何资源的 ​​std::unique_ptr​​​ 对象。 这里的 ​​nullptr_t​​​ 是从 ​​C++11​​​ 开始新增的类型, 表示空指针(​​nullptr​​​)的类型。
(2) 构造一个管理 ​​​p​​​ 指向资源的 ​​std::unique_ptr​​​ 对象。
(3) 构造一个管理 ​​​p​​​ 指向资源的 ​​std::unique_ptr​​​ 对象, 同时将释放资源的函数设置为 ​​d​​​。
(4) 构造一个管理 ​​​p​​​ 指向资源的 ​​std::unique_ptr​​​ 对象, 同时将释放资源的函数设置为 ​​d​​​。[主要针对 (3) 的 ​​d​​ 是右值引用类型时的重载]

  • ​conditional​​​: 在编译期,根据条件 B 进行 ​​typedef​​, ​​template< bool B, class T, class F > struct conditional;​​ 中, 如果 B 是 ​​true​​, 则定义为 ​​T​​ 类型, 如果 B 是 ​​false​​, 则定义为 ​​F​​ 类型。
  • ​is_reference​​:在编译期,判断某个类型是否是引用类型。
  • ​remove_reference​​​:在编译期移除某个类型的引用符号。如: ​​remove_reference<int&>::type​​ 类型就是 ​​int​​ 类型。
  • (3)(4)中的 ​​d​​ 的类型推导结果列举如下:
    a. 当 ​​Deleter​​ 是非引用类型 ​​A​​ 时,

unique_ptr(pointer p, const A& d); (3) unique_ptr(pointer p, A&& d); (4)

b. 当 ​​Deleter​​​ 是左值引用类型 ​​A&​​ 时,

unique_ptr(pointer p, A& d); (3) unique_ptr(pointer p, A&& d); (4)

c. 当 ​​Deleter​​​ 是 常左值引用类型 ​​const A&​​时,

unique_ptr(pointer p, const A& d); (3) unique_ptr(pointer p, const A&& d); (4)

(5) 利用移动语义,解决了 ​​auto_ptr​​​ 在构造函数上不足的地方。移动构造函数更能体现 ​​unique_ptr​​​ 在赋值时, 对资源的管理权的移交。
(6) 与 (5) 类似。主要针对隐式类型转化的情况。
(7) 实现从 ​​​auto_ptr​​​ 到 ​​unique_ptr​​ 的构造或赋值。

  • ​unique_ptr<T[]>​​​ 的构造函数。
    (略, 具体与 ​​unique_ptr<T>​​ 类似,细节处有略微差异)
  • 例子(取自 ​​cppreference.com​​)
#include <iostream>
#include <memory>

struct Foo { // object to manage
Foo() { std::cout << "Foo ctor\n"; }
Foo(const Foo&) { std::cout << "Foo copy ctor\n"; }
Foo(Foo&&) { std::cout << "Foo move ctor\n"; }
~Foo() { std::cout << "~Foo dtor\n"; }
};

struct D { // deleter
D() {};
D(const D&) { std::cout << "D copy ctor\n"; }
D(D&) { std::cout << "D non-const copy ctor\n";}
D(D&&) { std::cout << "D move ctor \n"; }
void operator()(Foo* p) const {
std::cout << "D is deleting a Foo\n";
delete p;
};
};

int main()
{
std::cout << "Example constructor(1)...\n";
std::unique_ptr<Foo> up1; // up1 is empty
std::unique_ptr<Foo> up1b(nullptr); // up1b is empty

std::cout << "\nExample constructor(2)...\n";
{
std::unique_ptr<Foo> up2(new Foo); //up2 now owns a Foo
} // Foo deleted

std::cout << "\nExample constructor(3)...\n";
D d;
{ // deleter type is not a reference
std::unique_ptr<Foo, D> up3(new Foo, d); // deleter copied
}
{ // deleter type is a reference
std::unique_ptr<Foo, D&> up3b(new Foo, d); // up3b holds a reference to d
}

std::cout << "\nExample constructor(4)...\n";
{ // deleter is not a reference
std::unique_ptr<Foo, D> up4(new Foo, D()); // deleter moved
}

std::cout << "\nExample constructor(5)...\n";
{
std::unique_ptr<Foo> up5a(new Foo);
std::unique_ptr<Foo> up5b(std::move(up5a)); // ownership transfer
}

std::cout << "\nExample constructor(6)...\n";
{
std::unique_ptr<Foo, D> up6a(new Foo, d); // D is copied
std::unique_ptr<Foo, D> up6b(std::move(up6a)); // D is moved

std::unique_ptr<Foo, D&> up6c(new Foo, d); // D is a reference
std::unique_ptr<Foo, D> up6d(std::move(up6c)); // D is copied
}

std::cout << "\nExample constructor(7)...\n";
{
std::auto_ptr<Foo> up7a(new Foo);
std::unique_ptr<Foo> up7b(std::move(up7a)); // ownership transfer
}
}

执行结果:

STL中的智能指针(Smart Pointer)及其源码剖析: std::unique_ptr

3. ​​unique_ptr的析构函数​​: 销毁管理的对象。

~unique_ptr();

如果 ​​*this​​​ 有管理的资源,则用 ​​deleter​​ 销毁该资源。

4. ​​拷贝赋值函数​

  • ​unique_ptr<T>​​ 的拷贝赋值函数。
unique_ptr& opertor=(unique_ptr&& r);           (1)

template<class U, class E>
unique_ptr& operator=(unique_ptr<U, E>&& r); (2)

unique_ptr& operator=(nullptr_t); (3)

(1) 将 ​​r​​​ 管理的资源的控制权移交给 ​​*this​​​,本身有管理的资源,则先用 ​​Deleter​​​ 释放该资源。[这里就是右值引用的好处了,曾记否,只有左值引用时代的 ​​auto_ptr​​​实现这个操作是多么的复杂。]
(2) 类似于 (1), 不过是针对 可隐式转换为该类型的 ​​​r​​​。
(3) 相当于调用 ​​​reset​​, 将管理资源的指针设为空。

  • ​unique_ptr<T[]>​​​ 的拷贝赋值函数。
    (略, 具体与 ​​unique_ptr<T>​​ 类似,细节处有略微差异)
  • 例子(改自 ​​cppreference.com​​)
#include <iostream>
#include <memory>

struct Foo {
Foo() { std::cout << "Foo\n"; }
~Foo() { std::cout << "~Foo\n"; }
};

int main()
{
std::unique_ptr<Foo> p1;

{
std::cout << "Creating new Foo...\n";
std::unique_ptr<Foo> p2(new Foo);

// p1 = p2; // Error ! can't copy unique_ptr
//unique_ptr& opertor=(unique_ptr&& r);
p1 = std::move(p2);
std::cout << "About to leave inner block...\n";

// Foo instance will continue to live,
// despite p2 going out of scope
}

// unique_ptr& operator=(nullptr_t);
std::cout << "Creating new Foo...\n";
std::unique_ptr<Foo> p3(new Foo);
std::cout << "Before p3 = nullptr...\n";
p3 = nullptr;
std::cout << "After p3 = nullptr...\n";

std::cout << "About to leave program...\n";
}

执行结果:

Creating new Foo...
Foo
About to leave inner block...
Creating new Foo...
Foo
Before p3 = nullptr...
~Foo
After p3 = nullptr...
About to leave program...
~Foo

6. 其他成员函数(​​unique_ptr::release​​​, ​​unique_ptr::reset​​​, ​​unique_ptr::swap​​​, ​​unique_ptr::get​​​, ​​unique_ptr::get_deleter​​​, ​​unique_ptr::operator bool​​​, ​​unique_ptr::operator*、unique_ptr::operator->​​, )

主要针对 ​​unique_ptr<T>​​​, 特化版本 ​​unique_ptr<T>​​ 与之类似。

pointer release();                            (1)

void reset(pointer ptr = pointer()); (2)

void swap(unique_ptr& other); (3)

pointer get() const; (4)

Deleter& get_deleter(); (5)
const Deleter& get_deleter() const; (6)

explicit operator bool() const; (7)

typename std::add_lvalue_reference<T>::type (8)
operator*() const;
pointer operator->() const; (9)

(1) 移交出 ​​*this​​​ 管理资源的指针。如果 ​​*this​​​ 没有管理资源,则返回 nullptr。
(2) 设置 ​​​*this​​​ 管理 ​​ptr​​​ 指向的资源, 如果 ​​*this​​​ 本身有管理的资源,则先用 ​​deleter​​​ 释放该资源。
(3) 将 ​​​*this​​​ 管理的资源和 ​​other​​​ 管理的资源进行交换。
(4) 获取 ​​​*this​​​ 管理资源的指针,如果没有被管理的资源则返回 ​​nullptr​​​。
(5) 获取 ​​​*this​​​ 绑定的 ​​deleter​​​。
(6) 与 (5) 类似。针对常类型。
(7) 隐式转换函数。判断是否 ​​​*this​​​ 管理有资源,如果是,则返回 ​​true​​​, 否则返回 ​​false​​。

关键字 ​​explicit​​​ 用在隐式转换函数前,限制该隐式转换函数,使其不能进行 ​​copy initialization​​。例如:

struct A { operator bool() const { return true; } }; struct B { explicit operator bool() const { return true; }; int main() { A a1; bool na1 = a1; // OK: copy-initialization selects A::operator bool() bool na2 = static_cast<bool>(a1); // OK: static_cast performs direct-initialization B b2; if (b2) ; // OK: B::operator bool() // bool nb1 = b2; // error: copy-initialization does not consider B::operator bool() bool nb2 = static_cast<bool>(b2); // OK: static_cast performs direct-initialization }

(8) 提供类似于指针的接口。获取 ​​*this​​​ 所管理的对象的左值引用。如果 ​​*this​​​ 没有管理对象,则该未定义该行为。
(9) 提供类似于指针的接口。获取 ​​​*this​​​ 所管理的对象的指针。如果 ​​*this​​ 没有管理对象,则该未定义该行为。

  • 例子
#include <iostream>
#include <memory>
#include <string>

using namespace std;

struct Foo {
Foo(string name = "Foo") : m_name(name)
{ std::cout << m_name << " is creating...\n"; }

~Foo() { std::cout << m_name << " is deleting...\n"; }
string m_name;
};

class FooDeleter{
public:
void Show() const { cout << "I'm FooDeleter..." << endl; }
void operator()(Foo* pf) const{
cout << "FooDeleter is deleting " << pf->m_name << endl;
delete pf;
}
};
int main()
{
{
// for realese()...
cout << "test for release()..." << endl << endl;
unique_ptr<Foo, FooDeleter> f1(new Foo("Foo f1"));
Foo* pf1 = f1.release(); // 将资源的管理权交给 pf1

cout << "before delete pf1..." << endl;
delete pf1;
cout << "after delete pf1..." << endl << endl;
}
cout << "--------------------------------" << endl << endl;
{
// for reset()...
cout << "test for reset()..." << endl << endl;
unique_ptr<Foo, FooDeleter> f2(new Foo("Foo f2"));
Foo* pf2 = new Foo("Foo pf2");

cout << "before f2.reset(pf2)..." << endl;
f2.reset(pf2);
cout << "after f2.reset(pf2)..." << endl << endl;
}
cout << "--------------------------------" << endl << endl;
{
// for swap()...
cout << "test for swap()..." << endl << endl;
unique_ptr<Foo, FooDeleter> f3(new Foo("Foo f3"));
unique_ptr<Foo, FooDeleter> f4(new Foo("Foo f4"), FooDeleter());

f3.swap(f4);

cout << "before f3.reset(nullptr)..." << endl;
f3.reset(nullptr);
cout << "after f3.reset(nullptr)..." << endl << endl;

cout << "before f4.reset(nullptr)..." << endl;
f4.reset(nullptr);
cout << "after f4.reset(nullptr)..." << endl << endl;

}
cout << "--------------------------------" << endl << endl;
{
// for get(), get_deleter(), operator bool(), operator*() and operator->()...
cout << "test for get(), get_deleter(), operator bool()" << endl
<< "operator*() and operator->()..." << endl << endl;

unique_ptr<Foo, FooDeleter> f5(new Foo("Foo f5"));
unique_ptr<Foo, FooDeleter> defaultF;

// for get()...
Foo* pf3 = f5.get();
cout << " f5.get()->m_name = " << pf3->m_name << endl;

// for get_deleter()...
FooDeleter& pd1 = f5.get_deleter();
pd1.Show();

// for operator bool()
if(f5) cout << "f5 == true" << endl;
if(!defaultF) cout << "defaultF == false" << endl;

// for operator*() and operator->()...
cout << "f5->m_name == " << f5->m_name << endl;
cout << "(*f5).m_name == " << (*f5).m_name << endl;
}
cout << "--------------------------------" << endl << endl;
}

运行结果:

test for release()...

Foo f1 is creating...
before delete pf1...
Foo f1 is deleting...
after delete pf1...

--------------------------------

test for reset()...

Foo f2 is creating...
Foo pf2 is creating...
before f2.reset(pf2)...
FooDeleter is deleting Foo f2
Foo f2 is deleting...
after f2.reset(pf2)...

FooDeleter is deleting Foo pf2
Foo pf2 is deleting...
--------------------------------

test for swap()...

Foo f3 is creating...
Foo f4 is creating...
before f3.reset(nullptr)...
FooDeleter is deleting Foo f4
Foo f4 is deleting...
after f3.reset(nullptr)...

before f4.reset(nullptr)...
FooDeleter is deleting Foo f3
Foo f3 is deleting...
after f4.reset(nullptr)...

--------------------------------

test for get(), get_deleter(), operator bool()
operator*() and operator->()...

Foo f5 is creating...
f5.get()->m_name = Foo f5
I'm FooDeleter...
f5 == true
defaultF == false
f5->m_name == Foo f5
(*f5).m_name == Foo f5
FooDeleter is deleting Foo f5
Foo f5 is deleting...
--------------------------------

二. unique_ptr 源码剖析(源码出自 Dev C++)

1. 辅助类 ​​template<typename _Tp> struct default_delete​​ 的源码

​default_delete​​​ 是 ​​unique_ptr​​ 绑定的默认 deleter。下面解析的是其泛化版本的源码(限于篇幅,针对数组的特化版本就不赘述了)。(代码中保留了 Dev C++ 的注释)

/// Primary template of default_delete, used by unique_ptr
template<typename _Tp>
struct default_delete
{
/// Default constructor
constexpr default_delete() noexcept = default; (1)

/** @brief Converting constructor.
*
* Allows conversion from a deleter for arrays of another type, @p _Up,
* only if @p _Up* is convertible to @p _Tp*.
*/
template<typename _Up, typename = typename (2)
enable_if<is_convertible<_Up*, _Tp*>::value>::type>
default_delete(const default_delete<_Up>&) noexcept { }

/// Calls @c delete @p __ptr
void operator()(_Tp* __ptr) const (3)
{
static_assert(!is_void<_Tp>::value, "can't delete pointer to incomplete type");
static_assert(sizeof(_Tp)>0, "can't delete pointer to incomplete type");

delete __ptr;
}
};

(1) deleter 的默认构造函数, 如果 ​​unique_ptr​​​ 的构造器没有传入 deleter 对象作为参数,需要在其内部默认构造一个 deleter 对象。
(2) 拷贝构造函数。由于没有加 ​​​explicit​​​ 限定符, 因此可以用做隐式转换。由于 ​​default_deleter​​​ 只是一个 ​​function object​​​,没有数据成员,因此实际上拷贝操作为空。
(3)该 ​​​funtion object​​​ 的主体,主要任务就是 ​​delete​​​ 掉传入的 ​​__ptr​​。

​std::is_convertible​​ 判断类型之间是否能成功转换的模板。

/// is_convertible template<typename _From, typename _To> (1) struct is_convertible :public __is_convertible_helper<_From, _To>::type { }; template<typename _From, typename _To, (2) bool = __or_<is_void<_From>, is_function<_To>, is_array<_To>>::value> struct __is_convertible_helper { typedef typename is_void<_To>::type type; }; template<typename _From, typename _To> class __is_convertible_helper<_From, _To, false> (3) { template<typename _To1>static void __test_aux(_To1); (3.1) template<typename _From1, typename _To1, (3.2) typename = decltype(__test_aux<_To1>(std::declval<_From1>()))> static true_type __test(int); template<typename, typename> (3.3) static false_type __test(...); public: typedef decltype(__test<_From, _To>(0)) type; (3.4) };

(1) 判断类型之间是否能成功转换的模板。实际上 ​​is_convertible​​​ 只是一个对外的口类, 类型转换的识别主要由其父类 ​​__is_convertible_helper​​​ 完成。
(2) 限于篇幅,这里就不对 ​​​__or_​​​, ​​is_void​​​ 和 ​​is_array​​​ 的源码进行分析了。从顾名思义, 在模板参数列表内判断 ​​_From​​​ 是不是 ​​void​​​ 类型, ​​_To​​​ 是不是函数类型, 或者 ​​_To​​​ 是不是数组类型。如果 ​​_From​​​ 是 ​​void​​​ 类型,则 ​​_To​​​ 只能为 ​​void​​​ 类型才能转换。 如果 ​​_To​​​ 是函数类型或者数组类型则不能实现转换。(​​type​​​ 类型是 ​​true_type​​​ 或 ​​false_type​​​ 类似,用于标识是否能完成转换。)
(3) 是 (2) 的特化版本。当 (2) 的默认模板参数识别出 ​​​false_type​​​ (该类的对象能隐式转换为 ​​false​​​, 有机会我会细讲其源码。), 就会进入 (3) 的特化版本。 其实 (2) 是针对特殊情况(​​_From​​​ 是 ​​void​​​ 类型, ​​_To​​​ 是函数类型, 或 ​​_To​​​ 是数组类型)的, 而 (3) 才是针对一般类似是否能实现转换的判断。
利用编译器所谓的 ​​​SFINAE​​​(Substitution Failure Is Not An Error) 技术, 实现对类型转换成功与否的判断。SFINAE, 即非模板函数具有最高优先权, 如果不存在匹配的非模板函数的话, 那么最匹配的和最特化的具有最高的优先权。
(3.1) 辅助函数声明。主要是利用静态模板函数声明, 实现在编译期获得其返回值类型(​​​void​​​的类型) 。 ​​decltype(__test_aux<_To1>(std::declval<_From1>()))​​​ 就是利用 ​​decltype​​​ 函数实现获取其返回值类型(​​void​​​ 类型)。当然,这里要求 ​​_From1​​​ 和 ​​_To1​​​ 类型一致(模板函数的使用…), 如果不一致,则编译不通过,根据 SFINAE 查找下一个匹配的模板。
(3.2) 当传入第三个模板参数默认为 ​​​decltype(__test_aux<_To1>(std::declval<_From1>()))​​​, 当 ​​_From1​​​ 和 ​​_To1​​​ 类型一致,则该参数为 ​​void​​​ 类型,如果不一致,则编译不通过,根据 SFINAE 查找下一个匹配的模板。
(3.3) 任意函数参数的两个模板参数的模板函数。
(3.4) 链接 (3.2) 和 (3.3) 的中枢。将 ​​​type​​​ 定义为 ​​__test<_From, _To>(0)​​​ 的类型, 根据模板推演原则, 首先选择需要一个函数参数 ​​__test​​​函数的模板函数, 即 (3.2)。但是, (3.2) 能成功推导的前提是 "​​_From1​​​ 和 ​​_To1​​​ 类型一致"。 如果一致,则​​type​​​ 被定义为 ​​true_type​​​ 类型((3.2) 的返回值的类型)。 如果不一致, 则根据 SFINAE, 选择下一个较次的匹配项进行模板推演,即(3.3), 则定义 ​​type​​​ 为 ​​false_type​​类型((3.3)的返回值类型)。

2. 辅助类 ​​_Pointer​​ 的源码(Dev C++ 实现的成员类, 非标准)

template <typename _Tp, typename _Dp = default_delete<_Tp> >         (0)
class unique_ptr;

// use SFINAE to determine whether _Del::pointer exists
class _Pointer
{
template<typename _Up> (1)
static typename _Up::pointer __test(typename _Up::pointer*);

template<typename _Up> (2)
static _Tp* __test(...);

typedef typename remove_reference<_Dp>::type _Del; (3)

public:
typedef decltype(__test<_Del>(0)) type; (4)
};

(0) Dev C++ 中 ​​unique_ptr​​​ 的声明。
(1) 如果 ​​​_Up::pointer​​​ 不存在, 则该声明不会被推导。
(2) 与 (1) 利用 ​​​SFINAE​​​ 一起判断 ​​_Up::pointer​​​ 是否存在。
(3) 将移除引用的 ​​​_Dp​​​ 类型定义为 ​​_Del​​​。
(4) 判断 ​​​_Del::pointer​​​ 是否存在的中枢。将 ​​__test<_Del>(0)​​​的返回值类型定义为 ​​type​​​。 根据模板推导原则, 首先选择含有一个函数参数的模板 (1), 如果 ​​_Up::pointer​​​ 存在,则推导成功, 将 ​​type​​​ 定义为 ​​_Up::pointer​​​ 类型((1) 的返回值类型); 如果 ​​_Up::pointer​​​ 不存在,根据 SFINAE, 编译器会接着选择较次的匹配, 即(2), 将 ​​type​​​ 定义为 ​​_Tp*​​((2)的返回值类型)。

题外话: 为什么不直接让 把 ​​type​​​ 设为 ​​_Tp*​​​ 呢?
答: 因为可能管理该资源的不是原始的指针, 而是用户定义的类似于指针的东西。如, 智能指针。

3. ​​unique_ptr​​ 的成员变量和成员类型

private:
typedef std::tuple<typename _Pointer::type, _Dp> __tuple_type; (1)
__tuple_type _M_t;

public:
typedef typename _Pointer::type pointer; (2)
typedef _Tp element_type; (3)
typedef _Dp deleter_type; (4)

(1) 定义 ​​tuple​​​ 的二元组类 ​​__tuple_type​​​, 存放所管理的资源的指针以及 deleter 对象。 并定义其对象 ​​_M_t​​​。
(2) 所管理资源的指针的类型。
(3) 所管理资源的了类型。
(4) 负责销毁资源的 deleter 的类型。

题外话: 多元组 ​​std::tuple​​​ 是用来存放任意数量不同类型的数据的集合。可以通过 ​​get<i>(tup)​​​ 来获取 ​​tup​​​ 的第 ​​i​​ 个元素。关于它的源码, 希望后续有时间能专门写博客来详细解读。

4. ​​unique_ptr​​ 构造函数的源码

// Constructors.

/// Default constructor, creates a unique_ptr that owns nothing.
constexpr unique_ptr() (1)
: _M_t(){}

/** Takes ownership of a pointer.
*
* @param __p A pointer to an object of @c element_type
*
* The deleter will be value-initialized.
*/
explicit unique_ptr(pointer __p) (2)
: _M_t(__p, deleter_type()) { }

/** Takes ownership of a pointer.
*
* @param __p A pointer to an object of @c element_type
* @param __d A reference to a deleter.
*
* The deleter will be initialized with @p __d
*/
unique_ptr(pointer __p, (3)
typename conditional<is_reference<deleter_type>::value,
deleter_type, const deleter_type&>::type __d)
: _M_t(__p, __d) { }

/** Takes ownership of a pointer.
*
* @param __p A pointer to an object of @c element_type
* @param __d An rvalue reference to a deleter.
*
* The deleter will be initialized with @p std::move(__d)
*/
unique_ptr(pointer __p, (4)
typename remove_reference<deleter_type>::type&& __d)
: _M_t(std::move(__p), std::move(__d)) { }

/// Creates a unique_ptr that owns nothing.
constexpr unique_ptr(nullptr_t) : unique_ptr() { } (5)

// Move constructors.

/// Move constructor.
unique_ptr(unique_ptr&& __u) (6)
: _M_t(__u.release(),
std::forward<deleter_type>(__u.get_deleter())) { }

/** @brief Converting constructor from another type
*
* Requires that the pointer owned by @p __u is convertible to the
* type of pointer owned by this object, @p __u does not own an array,
* and @p __u has a compatible deleter type.
*/
template<typename _Up, typename _Ep, (7)
typename = _Require<is_convertible<typename unique_ptr<_Up, _Ep>::pointer, pointer>, __not_<is_array<_Up>>,
typename conditional<is_reference<_Dp>::value, is_same<_Ep, _Dp>,
is_convertible<_Ep, _Dp>>::type>>
unique_ptr(unique_ptr<_Up, _Ep>&& __u)
: _M_t(__u.release(), std::forward<_Ep>(__u.get_deleter()))
{ }

#if _GLIBCXX_USE_DEPRECATED
/// Converting constructor from @c auto_ptr
template<typename _Up, (8)
typename = _Require<is_convertible<_Up*, _Tp*>, is_same<_Dp, default_delete<_Tp>>>>
unique_ptr(auto_ptr<_Up>&& __u);
#endif

(1) 默认构造函数。只是创建 ​​unique_ptr​​​ 对象, 并没有管理资源。
(2) 构造管理 ​​​__p​​​ 指向的资源的构造函数。 并将其 deleter 设为 ​​deleter_type​​​ 默认构造的 deleter。
(3) 这个构造函数的声明在 ​​​unique_ptr​​​ 的使用部分已经介绍过了。构造管理指针 ​​__p​​​ 指向的资源, 并且设置其 deleter 为 ​​__d​​​ 的构造函数。
(4) 这个构造函数的声明也在 ​​​unique_ptr​​​ 的使用部分已经介绍过了。 与 (3) 类似,不过是针对 ​​__d​​​ 是右值引用的情况。关于 ​​std::move​​​的相关知识,以后有机会细讲。
(5) 构造不管理任何资源的 ​​​unique_ptr​​​ 对象。
(6) 移动构造函数。与 ​​​auto_ptr​​​ 类似, ​​unique_ptr​​​ 不与他人共同管理资源。实际上只需要实现其移动构造函数即可。​​std::forward​​​ 使其参数按照原来的值类型传递。
(7) 用满足要求的能转换为 ​​​*this​​​ 管理类型的资源的 ​​__u​​​, 移动构造或隐式转换为 ​​*this​​​。
(8) 如果还有 ​​​auto_ptr​​​ 可用的话, 就加上从 ​​auto_ptr​​​ 到 ​​unique_ptr​​ 的移动构造(隐式转换)函数。

5. ​​unique_ptr​​ 析构函数

/// Destructor, invokes the deleter if the stored pointer is not null.
~unique_ptr()
{
auto& __ptr = std::get<0>(_M_t); (1)

if (__ptr != nullptr) (2)
get_deleter()(__ptr);

__ptr = pointer(); (3)
}

(1) ​​_M_t​​​ 内依次是 ​​*this​​​ 管理的资源和绑定的 deleter。所以 ptr实际上获得的是 ​​*this​​​ 管理资源的指针的引用。
(2) 如果 ​​​__ptr != nullptr​​​, 即 ​​*this​​​ 有管理的对象, 则用 deleter 将该资源销毁。
(3) 重置管理指针。

6. ​​unique_ptr​​ 移动赋值函数

// Assignment.
/** @brief Move assignment operator.
*
* @param __u The object to transfer ownership from.
*
* Invokes the deleter first if this object owns a pointer.
*/
unique_ptr& operator=(unique_ptr&& __u) (1)
{
reset(__u.release());
get_deleter() = std::forward<deleter_type>(__u.get_deleter());
return *this;
}

/** @brief Assignment from another type.
*
* @param __u The object to transfer ownership from, which owns a
* convertible pointer to a non-array object.
*
* Invokes the deleter first if this object owns a pointer.
*/
template<typename _Up, typename _Ep> (2)
typename enable_if< __and_<
is_convertible<typename unique_ptr<_Up, _Ep>::pointer, pointer>,
__not_<is_array<_Up>>
>::value,
unique_ptr&>::type operator=(unique_ptr<_Up, _Ep>&& __u)
{
reset(__u.release());
get_deleter() = std::forward<_Ep>(__u.get_deleter());
return *this;
}

/// Reset the %unique_ptr to empty,invoking the deleter if necessary.
unique_ptr& operator=(nullptr_t) (3)
{
reset();
return *this;
}

(1) 移动赋值函数。相较于 ​​auto_ptr​​​ 复杂的实现, 有移动语义的 ​​unique_ptr​​​ 的赋值函数更加简洁。 为了防止自我赋值产生奇怪错误, 这里用 ​​__u.release()​​​ 函数返回控制资源的指针, 然后 ​​reset​​​ 给 ​​*this​​​。
(2) 针对可转化为 ​​​*this​​​ 的 ​​unique_ptr​​​ 的重载版本, 实现细节与 (1) 类似。
(3) 用 ​​​nullptr​​​ 赋值给 ​​*this​​​。 实际上就是将 ​​*this​​ 管理的资源清空。

7. ​​unique_ptr​​ 其他函数

/// Dereference the stored pointer.
typename add_lvalue_reference<element_type>::type operator*() const (1)
{
return *get();
}
/// Return the stored pointer.
pointer operator->() const (2)
{
return get();
}

/// Return the stored pointer.
pointer get() const (3)
{ return std::get<0>(_M_t); }
/// Return a reference to the stored deleter.
deleter_type& get_deleter() (4)
{ return std::get<1>(_M_t); }
/// Return a reference to the stored deleter.
const deleter_type& get_deleter() const (4)
{ return std::get<1>(_M_t); }

/// Return @c true if the stored pointer is not null.
explicit operator bool() const (5)
{ return get() == pointer() ? false : true; }

/// Release ownership of any stored pointer.
pointer release() (6)
{
pointer __p = get();
std::get<0>(_M_t) = pointer();
return __p;
}

/** @brief Replace the stored pointer.
*
* @param __p The new pointer to store.
*
* The deleter will be invoked if a pointer is already owned.
*/
void reset(pointer __p = pointer()) (7)
{
using std::swap;
swap(std::get<0>(_M_t), __p);
if (__p != pointer())
get_deleter()(__p);
}

/// Exchange the pointer and deleter with another object.
void swap(unique_ptr& __u) (8)
{
using std::swap;
swap(_M_t, __u._M_t);
}

// Disable copy from lvalue.
unique_ptr(const unique_ptr&) = delete; (9)
unique_ptr& operator=(const unique_ptr&) = delete;

(1) 重载 ​​operator*()​​​。通过 ​​get()​​​ 函数获取 ​​*this​​​ 管理的资源的引用。
(2) 重载 ​​​operator->()​​​。通过 ​​get()​​​ 函数获取 ​​*this​​​ 管理的资源的指针。
(3) 从二元组 ​​​std::tuple<typename _Pointer::type, _Dp>​​​ 中获取 ​​*this​​​ 管理的资源的指针。
(4) 从二元组 ​​​std::tuple<typename _Pointer::type, _Dp>​​​ 中获取 ​​*this​​​ 绑定的 deleter 的 (常) 引用。
(5) 隐式转换为布尔类型的函数。前面有解释过 ​​​explicit​​​ 的作用。用于判断 ​​*this​​​ 是否有管理的资源。
(6) 移交出 ​​​*this​​​ 管理的资源。 先让 ​​__p​​​ 保存 ​​*this​​​ 管理的资源, 然后让 ​​*this​​​ 的 管理指针置零, 最后返回 ​​__p​​​。
(7) 更改 ​​​*this​​​ 管理的资源。为了防止 ​​__p == this​​​ 时错误的销毁了该资源, 用 ​​swap​​​ 函数交换资源, 然后用 deleter 删除交换给原始指针的资源。
(8) 交换两个 ​​​unique_ptr​​​ 所管理的资源。 实际上就是交换其二元组 ​​std::tuple<typename _Pointer::type, _Dp>​​​。
(9) 由于 ​​​unique_ptr​​ 要求必须单独管理资源, 不能同时管理资源, 因此拷贝赋值函数实际上是没有意义的, 因此需要删除。

三. 总结

​unique_ptr​​​ 的功能与 ​​auto_ptr​​​ 类似, 都是按照 RAII 原则, 实现单独对资源的管理。 相较于 ​​auto_ptr​​​, ​​unique_ptr​​​ 更进一步的是: ​​unique_ptr​​​ 有右值引用以及强大的C++新特性的加持, 因此在很多实现上更加的完美; ​​unique_ptr​​ 可以设置销毁资源的 deleter, 这就使得它不仅可以管理内存资源, 也可以管理其它的需要释放的资源(需要设置对应的deleter)。

四. 参考文献