Skip to the content.

18 用 std::unique_ptr 管理所有权唯一的资源

struct A {};

std::unique_ptr<A> make_a() { return std::unique_ptr<A>{new A}; }

auto p = make_a();
struct A {};

auto f = [](A* p) {
  std::cout << "destroy\n";
  delete p;
};

std::unique_ptr<A, decltype(f)> make_a() {
  std::unique_ptr<A, decltype(f)> p{new A, f};
  return p;
}
struct A {};

auto make_a() {
  auto f = [](A* p) {
    std::cout << "destroy\n";
    delete p;
  };
  std::unique_ptr<A, decltype(f)> p{new A, f};
  return p;
}
struct A {
  // 删除器对任何对象调用的是基类的析构函数,因此必须声明为虚函数
  virtual ~A() = default;
};
// 基类的析构函数为虚函数,则派生类的析构函数默认为虚函数
struct B : A {};  
struct C : A {};
struct D : A {};

auto make_a(int i) {
  auto f = [](A* p) {
    std::cout << "destroy\n";
    delete p;
  };
  std::unique_ptr<A, decltype(f)> p{nullptr, f};
  if (i == 1) {
    p.reset(new B);
  } else if (i == 2) {
    p.reset(new C);
  } else {
    p.reset(new D);
  }
  return p;
}
struct A {};

auto f = [](A* p) { delete p; };

void g(A* p) { delete p; }

struct X {
  void operator()(A* p) const { delete p; }
};

std::unique_ptr<A> p1{new A};
std::unique_ptr<A, decltype(f)> p2{new A, f};
std::unique_ptr<A, decltype(g)*> p3{new A, g};
std::unique_ptr<A, decltype(X())> p4{new A, X{}};

static_assert(sizeof(p1) == sizeof(nullptr));  // 默认尺寸,即一个原始指针的尺寸
static_assert(sizeof(p2) == sizeof(nullptr));  // 无捕获 lambda 不会浪费尺寸
static_assert(sizeof(p3) == sizeof(nullptr) * 2);  // 函数指针占一个原始指针尺寸
static_assert(sizeof(p4) == sizeof(nullptr));  // 无状态的函数对象,但如果函数对象有状态(如数据成员、虚函数)就会增加尺寸
// std::make_unique 的返回类型是 std::unique_ptr
std::shared_ptr<int> p = std::make_unique<int>(42);
#include <cassert>
#include <memory>

int main() {
  std::unique_ptr<int[]> p{new int[3]{0, 1, 2}};
  for (int i = 0; i < 3; ++i) {
    assert(p[i] == i);
  }
}

19 用 std::shared_ptr 管理所有权可共享的资源

int* p = new int{42};
auto q = std::make_shared<int>(42);
static_assert(sizeof(p) == sizeof(nullptr));
static_assert(sizeof(q) == sizeof(nullptr) * 2);
class A {};
auto f = [](A* p) { delete p; };

std::unique_ptr<A, decltype(f)> p{new A, f};
std::shared_ptr<A> q{new A, f};
std::shared_ptr<A> p{new A, f};
std::shared_ptr<A> q{new A, g};
// 使用不同的删除器但具有相同的类型,因此可以放进同一容器
std::vector<std::shared_ptr<A>> v{p, q};

#include <cassert>
#include <memory>

int main() {
  auto p = std::make_shared<int>(0);
  std::shared_ptr<int> q(p, new int(1));
  assert(*q == 1);
  assert(p.use_count() == 2);
  assert(q.use_count() == 2);
  p.reset();
  assert(p.use_count() == 0);
  assert(q.use_count() == 1);
  // 再次共享时引用计数为 0,但内部却可以保存值
  std::shared_ptr<int> p2(p, new int(2));
  assert(*p2 == 2);
  assert(p.use_count() == 0);
  assert(q.use_count() == 1);
  assert(p2.use_count() == 0);
}
template <class T, class U>
std::shared_ptr<T> dynamic_pointer_cast(const std::shared_ptr<U>& r) noexcept {
  if (auto p =
          dynamic_cast<typename std::shared_ptr<T>::element_type*>(r.get())) {
    return std::shared_ptr<T>(r, p);  // 返回值与源指针共享所有权
  } else {
    return std::shared_ptr<T>();
  }
}
template <typename T>
struct sp_element {
  using type = T;
};

template <typename T>
struct sp_element<T[]> {
  using type = T;
};

template <typename T, std::size_t N>
struct sp_element<T[N]> {
  using type = T;
};

template <typename T>
class shared_ptr {
  using elem_type = typename sp_element<T>::type;
  elem_type* px;    // 内部指针
  shared_count pn;  // 引用计数
  template <typename U>
  friend class shared_ptr;
  template <typename U>
  friend class weak_ptr;
};

class shared_count {
  sp_counted_base* pi;
  int shared_count_id;
  friend class weak_count;
};

class weak_count {
  sp_counted_base* pi;
};

class sp_counted_base {
  int use_count;   // 引用计数
  int weak_count;  // 弱引用计数
};

template <typename T>
class sp_counted_impl_p : public sp_counted_base {
  T* px;  // 删除器
};
class sp_counted_base {
 private:
  std::atomic_int_least32_t use_count_;  // 即 std::atomic<int>
  std::atomic_int_least32_t weak_count_;

 public:
  sp_counted_base() : use_count_(1), weak_count_(1) {}
  virtual ~sp_counted_base() {}
  virtual void dispose() = 0;
  virtual void destroy() { delete this; }

  void add_ref_copy() { atomic_increment(&use_count_); }

  bool add_ref_lock() { return atomic_conditional_increment(&use_count_) != 0; }

  void release() {
    if (atomic_decrement(&use_count_) == 1) {
      dispose();
      weak_release();
    }
  }

  void weak_add_ref() { atomic_increment(&weak_count_); }

  long use_count() const { return use_count_.load(std::memory_order_acquire); }
};
#include <memory>

int main() {
  {
    int* i = new int{42};
    std::shared_ptr<int> p{i};
    std::shared_ptr<int> q{i};
  }  // 错误
}
auto p = std::make_shared<int>(42);
auto f = [](int*) {};
std::shared_ptr<int> p{new int(42), f};
#include <cassert>
#include <memory>

class A {
 public:
  std::shared_ptr<A> f() { return std::shared_ptr<A>(this); }
};

int main() {
  {
    auto p = std::make_shared<A>();
    auto q = p->f();
    assert(p.use_count() == 1);
    assert(q.use_count() == 1);
  }  // ERROR
}
#include <memory>

template <typename T>
void callback(const T& p) {
  p->print();
}

class A {
 public:
  void f() { callback(std::shared_ptr<A>(this)); }
  void print() {}
};

int main() {
  {
    auto p = std::make_shared<A>();
    p->f();  // 调用结束时析构 std::shared_ptr<A>(this),p 中的对象被析构
  }          // ERROR:再次析构
}
#include <cassert>
#include <memory>

class A : public std::enable_shared_from_this<A> {
 public:
  std::shared_ptr<A> f() { return shared_from_this(); }
};

int main() {
  {
    auto p = std::make_shared<A>();
    auto q = p->f();
    assert(p.use_count() == 2);
    assert(q.use_count() == 2);
  }  // OK
}
template <class T>
class enable_shared_from_this {
 public:
  shared_ptr<T> shared_from_this() {
    shared_ptr<T> p(weak_this_);
    return p;
  }

 public:
  /*
   * 构造 shared_ptr<A> 时
   * 如果 A 继承了 enable_shared_from_this<A>
   * 则调用此函数
   */
  template <class X, class Y>
  void _internal_accept_owner(const shared_ptr<X>* ppx, Y* py) {
    if (weak_this_.expired()) {
      // alias constructor,共享 *ppx 的引用计数,但指向 py
      weak_this_ = shared_ptr<T>(*ppx, py);
    }
  }

 private:
  weak_ptr<T> weak_this_;
};

template <class T>
class shared_ptr {
 public:
  template <class Y>
  explicit shared_ptr(Y* p) : px(p), pn() {
    boost::detail::sp_pointer_construct(this, p, pn);
  }

  template <class T, class Y>
  void sp_pointer_construct(boost::shared_ptr<T>* ppx, Y* p,
                            boost::detail::shared_count& pn) {
    boost::detail::shared_count(p).swap(pn);
    boost::detail::sp_enable_shared_from_this(ppx, p, p);
  }

  template <class X, class Y, class T>
  void sp_enable_shared_from_this(boost::shared_ptr<X> const* ppx, Y const* py,
                                  boost::enable_shared_from_this<T> const* pe) {
    if (pe != 0) {
      pe->_internal_accept_owner(ppx, const_cast<Y*>(py));  // ppx 和 py 一致
    }
  }

  void sp_enable_shared_from_this(...) {
  }  // 如果第三个参数不能转为 enable_shared_from_this 则调用此函数

  shared_ptr(shared_ptr<Y> const& r, element_type* p)
      : px(p), pn(r.pn) {}  // alias constructor,共享引用计数但指向不同对象

 private:
  using elem_type = typename sp_element<T>::type;
  element_type* px;                // 内部指针
  boost::detail::shared_count pn;  // 控制块,包含引用计数、删除器
}
#include <memory>

class A : public std::enable_shared_from_this<A> {
 public:
  std::shared_ptr<A> f() { return shared_from_this(); }
};

int main() {
  auto p = new A;
  auto q = p->f();  // 抛出 std::bad_weak_ptr 异常
}
#include <memory>

class A : public std::enable_shared_from_this<A> {
 public:
  static std::shared_ptr<A> create() { return std::shared_ptr<A>(new A); }
  std::shared_ptr<A> f() { return shared_from_this(); }

 private:
  A() = default;
};

int main() {
  auto p = A::create();  // 构造函数为 private,auto p = new A 将报错
  auto q = p->f();       // OK
}
#include <type_traits>

// 检测 T* 能否转为 T::_Esft_type*
template <class T, class = void>
struct _enable_shared : false_type {};

template <class T>
struct _enable_shared<T, void_t<typename T::_Esft_type>>
    : is_convertible<remove_cv_t<T>*, typename T::_Esft_type*>::type {};

template <class T>
class shared_ptr {
 public:
  template <class Y>
  explicit shared_ptr(Y* px) {
    _Set_ptr_rep_and_enable_shared(px, new _Ref_count<Y>(px));
  }

  template <class Y>
  void _Set_ptr_rep_and_enable_shared(Y* const px, _Ref_count_base* const pn) {
    this->_Ptr = px;
    this->_Rep = pn;
    if constexpr (_enable_shared<Y> >) {
      if (px && px->_Wptr.expired()) {
        px->_Wptr =
            shared_ptr<remove_cv_t<Y>>(*this, const_cast<remove_cv_t<Y>*>(px));
      }
    }
  }
}
#include <cassert>
#include <memory>

template <typename T>
class B {
 public:
  using _Esft_type = B;  // 定义 _Esft_type 且派生类指针要能转为 _Esft_type*

  std::shared_ptr<T> my_shared_from_this() { return std::shared_ptr<T>(_Wptr); }

 private:
  template <class U>
  friend class std::shared_ptr;

  std::weak_ptr<T> _Wptr;  // 提供一个名为 _Wptr 的 weak_ptr
};

class A : public B<A> {
 public:
  std::shared_ptr<A> f() { return my_shared_from_this(); }
};

int main() {
  {
    auto p = std::make_shared<A>();
    auto q = p->f();
    assert(p.use_count() == 2);
    assert(q.use_count() == 2);
  }  // OK
}

20 用 std::weak_ptr 观测 std::shared_ptr 的内部状态

#include <cassert>
#include <iostream>
#include <memory>

std::weak_ptr<int> w;

void f(std::weak_ptr<int> w) {
  if (auto p = w.lock()) {
    std::cout << *p;
  } else {
    std::cout << "can't get value";
  }
}

int main() {
  {
    auto p = std::make_shared<int>(42);
    w = p;
    assert(p.use_count() == 1);
    assert(w.expired() == false);
    f(w);  // 42
    auto q = w.lock();
    assert(p.use_count() == 2);
    assert(q.use_count() == 2);
  }
  f(w);  // can't get value
  assert(w.expired() == true);
  assert(w.lock() == nullptr);
}
#include <cassert>
#include <iostream>
#include <memory>

class B;
class A {
 public:
  std::shared_ptr<B> b;
  virtual ~A() { std::cout << "destroy A\n"; }
};

class B {
 public:
  std::weak_ptr<A> a;
  virtual ~B() { std::cout << "destroy B\n"; }
};

int main() {
  {
    auto p = std::make_shared<A>();
    p->b = std::make_shared<B>();
    p->b->a = p;
    assert(p.use_count() == 1);
  }  // p.use_count() 由 1 减为 0,从而正常析构
  // 若将 weak_ptr 改为 shared_ptr,p.use_count() 为 2,此处减为 1,不会析构
  // 此时 p->b 也不会析构,导致两次内存泄漏
}

21 用 std::make_uniquestd::make_shared) 创建 std::unique_ptrstd::shared_ptr

template <typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args) {
  return std::unique_ptr<T>{new T{std::forward<Args>(args)...}};
}
auto p = std::make_unique<int>(42);
std::unique_ptr<int> q{new int{42}};
void f(std::shared_ptr<A> p, int n) {}
int g() { return 1; }
f(std::shared_ptr<A>{new A}, g());  // 潜在的内存泄露隐患
// g 可能运行于 new A 还未返回给 std::shared_ptr 的构造函数时
// 此时如果 g 抛出异常,则 new A 就发生了内存泄漏
std::shared_ptr<A> p(new A);  // 如果发生异常,删除器将析构 new 创建的对象
f(std::move(p), g());

f(std::make_shared<A>(), g());  // 不会发生内存泄漏,且只需要一次内存分配
auto f = [](A* p) { delete p; };
std::unique_ptr<A, decltype(f)> p{new A, f};
std::shared_ptr<A> q{new A, f};
auto d = [](A* p) { delete p; };
std::shared_ptr<A> p{new A, d};  // 如果发生异常,删除器将析构 new 创建的对象
f(std::move(p), g());
auto p = std::make_unique<std::vector<int>>(3, 6);  // vector 中是 3 个 6
auto q = std::make_shared<std::vector<int>>(3, 6);  // vector 中是 3 个 6

auto x = {1, 2, 3, 4, 5, 6};
auto p2 = std::make_unique<std::vector<int>>(x);
auto q2 = std::make_shared<std::vector<int>>(x);
auto p = std::make_shared<ReallyBigType>();
  // 创建指向该对象的多个 std::shared_ptr 和 std::weak_ptr 并做一些操作
  // 最后一个 std::shared_ptr 被析构,但 std::weak_ptr 仍存在
  // 此时,大尺寸对象占用内存仍未被回收
  // 最后一个 std::weak_ptr 被析构,control block 和对象占用的同一内存块被释放
std::shared_ptr<ReallyBigType> p(new ReallyBigType);
  // 创建指向该对象的多个 std::shared_ptr 和 std::weak_ptr 并做一些操作
  // 最后一个 std::shared_ptr 被析构,std::weak_ptr 仍存在,但 ReallyBigType 占用的内存立即被释放
  // 此时,仅 control block 内存处于分配而未回收状态
  // 最后一个 std::weak_ptr 被析构,control block 的内存块被释放

22 用 std::unique_ptr 实现 pimpl 必须在源文件中提供析构函数定义

// A.h
#include <string>
#include <vector>

class A {
 private:
  int i;
  std::string s;
  std::vector<double> v;
};
// A.h
class A {
 public:
  A();
  ~A();

 private:
  struct X;
  X* x;
};

// A.cpp
#include <string>
#include <vector>

#include "A.h"


struct A::X {
  int i;
  std::string s;
  std::vector<double> v;
};

A::A() : x(new X) {}
A::~A() { delete x; }
// A.h
#include <memory>

class A {
 public:
  A();

 private:
  struct X;
  std::unique_ptr<X> x;
};

// A.cpp
#include <string>
#include <vector>

#include "A.h"


struct A::X {
  int i;
  std::string s;
  std::vector<double> v;
};

A::A() : x(std::make_unique<X>()) {}
// main.cpp
#include "A.h"

int main() {
  A a;  // 错误:A::X 是不完整类型
}
// 删除器的实现
template <class T>
struct default_delete {  // default deleter for unique_ptr
  constexpr default_delete() noexcept = default;

  template <class U, enable_if_t<is_convertible_v<U*, T*>, int> = 0>
  default_delete(const default_delete<U>&) noexcept {}

  void operator()(T* p) const noexcept {
    static_assert(0 < sizeof(T), "can't delete an incomplete type");
    delete p;
  }
};
// A.h
#include <memory>

class A {
 public:
  A();
  ~A();

 private:
  struct X;
  std::unique_ptr<X> x;
};

// A.cpp
#include <string>
#include <vector>

#include "A.h"


struct A::X {
  int i;
  std::string s;
  std::vector<double> v;
};

A::A() : x(std::make_unique<X>()) {}
A::~A() = default;  // 必须位于 A::X 的定义之后
// A.h
#include <memory>

class A {
 public:
  A();
  ~A();
  A(A&&) = default;
  A& operator=(A&&) = default;

 private:
  struct X;
  std::unique_ptr<X> x;
};

// A.cpp
#include <string>
#include <vector>

#include "A.h"


struct A::X {
  int i;
  std::string s;
  std::vector<double> v;
};

A::A() : x(std::make_unique<X>()) {}
A::~A() = default;  // 必须位于 A::X 的定义之后
// main.cpp
#include "A.h"

int main() {
  A a;
  A b(std::move(a));   // 错误:使用了未定义类型 A::X
  A c = std::move(a);  // 错误:使用了未定义类型 A::X
}
// A.h
#include <memory>

class A {
 public:
  A();
  ~A();
  A(A&&);
  A& operator=(A&&);

 private:
  struct X;
  std::unique_ptr<X> x;
};

// A.cpp
#include <string>
#include <vector>

#include "A.h"


struct A::X {
  int i;
  std::string s;
  std::vector<double> v;
};

A::A() : x(std::make_unique<X>()) {}
A::A(A&&) = default;
A& A::operator=(A&&) = default;
A::~A() = default;
// A.h
#include <memory>

class A {
 public:
  A();
  ~A();
  A(A&&);
  A& operator=(A&&);
  A(const A&);
  A& operator=(const A&);

 private:
  struct X;
  std::unique_ptr<X> x;
};

// A.cpp
#include <string>
#include <vector>

#include "A.h"

struct A::X {
  int i;
  std::string s;
  std::vector<double> v;
};

A::A() : x(std::make_unique<X>()) {}
A::A(A&&) = default;
A& A::operator=(A&&) = default;
A::~A() = default;
A::A(const A& rhs) : x(std::make_unique<X>(*rhs.x)) {}
A& A::operator=(const A& rhs) {
  *x = *rhs.x;
  return *this;
}
// A.h
#include <memory>

class A {
 public:
  A();

 private:
  struct X;
  std::shared_ptr<X> x;
};

// A.cpp
#include <string>
#include <vector>

#include "A.h"

struct A::X {
  int i;
  std::string s;
  std::vector<double> v;
};

A::A() : x(std::make_shared<X>()) {}