C++11 Smart Pointer: auto_ptr is deprecated. Use other smart pointers.
我们在 C++ Exception Handling / auto_ptr 里介绍了 RAII wrapper for pointers: auto_ptr,但是它在 C++11 又被 deprecated 了……对应的 replacement 是 unique_ptr。顺带还推出了 shared_ptr 和 weak_ptr。

(Diagram Credit: Learn C++ By Example by Frances Buontempo)
1. Header
#include <memory>
2. unique_ptr / make_unique
unique_ptr:
- A
unique_ptr100% owns the underlying object - $\mathtt{copy}$ is disabled
 - $\mathtt{move}$ is allowed
 - Then underlying object is destroyed when its 
unique_ptris destroyed (i.e. 强联动) 
unique_ptr 的创建方式有很多,常见的有两种:
- 从一个 vanilla pointer 构建
 - 用 
make_unique 
“从 vanilla pointer 构建” 这个方法有一个问题:你是可以用同一个 vanilla pointer 构建出两个 unique_ptr 的,第二个 unique_ptr 销毁时会导致 UB (undefined behavior)
#include <memory>
using namespace std;
int val = 42;
int* pval = &val;
unique_ptr<int> up1(pval);  // OK. can be destroyed normally
unique_ptr<int> up2(pval);  // UB. when being destroyed, the underlying int is already destroyed
所以一般 recommend 用 make_unique (See C++ Core Guidelines - R.23):
auto up3 = make_unique<int>(42);  // OK. pointing to an integer of 42
auto up4 = make_unique<int>(42);  // OK. pointing to another integer of 42
make_unique 的语法一般是:
make_unique<T>(arg1, arg2, ...);  // pointing to T(arg1, arg2, ...)
但 make_unique 本质是一个 variadic template,所以你可以 explicitly 指定 arg1, arg2, ... 的 type,只是一般没啥必要:
make_unique<T, T_ARG1, T_ARG2, ...>(arg1, arg2, ...);  // pointing to T(arg1, arg2, ...)
3. shared_ptr/ make_shared
shared_ptr:
- Multiple 
shared_ptrs can own the same underlying object - Just like reference counting, there is a shared count stored in 
control block - The underlying object is destroyed when all 
shared_ptrs are destroyed or go out of scope, i.e. when the shared count decreased to 0 
shared_ptr 是可以 “从同一个 vanilla pointer 构建多个” 的,但仍然推荐用 make_shared (See C++ Core Guidelines - R.22)
int val = 42;
int* pval = &val;
shared_ptr<int> sp1(pval);  // OK
shared_ptr<int> sp2(pval);  // OK
auto sp3 = make_shared<int>(42);  // pointing to an integer of 42
auto sp4 = shared_ptr<int>(sp3);  // OK. copy-construction from sp3
                                  // pointing to the same integer of 42, as sp3 is
sp4.use_count;  // == 2. 这个 field 即是 shared count
4. weak_ptr / make_weak
make_weak使用 shared_ptr 可能有 cyclic dependency 的问题,简单说就是:class A 持有一个 shared_ptr<B>,同时 class B 持有一个 shared_ptr<A>。这个问题有多种解决方案,其中之一是把 shared_ptr 改成 weak_ptr。(See C++ Core Guidelines - R.24)
weak_ptr 的创建,有:
- ⭕ 从另一个 
weak_ptr$\mathtt{copy}$-construct - ⭕ 从另一个 
weak_ptr$\mathtt{move}$-construct - ⭕ 从另一个 
shared_ptr$\mathtt{copy}$-construct - ❌ 从另一个 
shared_ptr$\mathtt{move}$-construct - ❌ 从另一个 
unique_ptr$\mathtt{copy}$-construct - ❌ 从另一个 
unique_ptr$\mathtt{move}$-construct 
最常见的创建方法就是 “从另一个 shared_ptr $\mathtt{copy}$-construct”,注意这种情况下,weak_ptr 不参与 shared_ptr 的 shared counting (可以参考 My blog Understanding Weak References)。正因为这个原因,weak_ptr 所指向的 object 可能是已经销毁的,所以 access 之前需要确认一下:
auto sp = make_shared<int>(42);
weak_ptr<int> wp = sp;  // copy-construct
wp.use_count();  // == 1. 实际是 sp.use_count()
wp.expired();    // bool. whether the referenced object is already destroyed
wp.lock();       // returns `expired() ? shared_ptr<T>() : shared_ptr<T>(*this)`
if (shared_ptr<int> new_sp = wp.lock())  // N.B. new `shared_ptr` created here
    cout << "wp is not expired. value == " << *new_sp << endl;
else
    cout << "wp is expired."; << endl;
另外不存在 make_weak 函数。
5. Deleter
unique_ptr 和 shared_ptr 都可以在创建时附带一个 Deleter d,比如:
template< typename Y, typename Deleter >  
shared_ptr( Y* ptr, Deleter d );
要求是 d(ptr) 必须是 well-formed。我们一般会用 Deleter 去处理额外的、特殊的 “资源释放” 的任务。
你可以把 Deleter 实现成:
- a struct/class with 
void operator()(Y* ptr),或者 - a 
std::function,或者 - a lambda
 
留下评论