头文件 #include <memory>

std::auto_ptr

  1. #include <iostream>
  2. #include <memory>
  3. using namespace std;
  4. class T {
  5. public:
  6. T() {
  7. cout << "constructor called" << endl;
  8. }
  9. ~T() {
  10. cout << "destructor called" << endl;
  11. }
  12. };
  13. int main() {
  14. cout << "--------begin-----------" << endl;
  15. {
  16. cout << 1 << endl;
  17. auto_ptr<T> t1(new T);
  18. cout << 2 << endl;
  19. auto_ptr<T> t2 = t1; // 此处会让t1的指向变成null
  20. cout << 3 << endl;
  21. if (!t1.get()) {
  22. cout << "t1 is null" << endl;
  23. }
  24. cout << 4 << endl;
  25. }
  26. cout << "--------end-----------" << endl;
  27. return 0;
  28. }

auto_ptr在copy、assignment时会使得源指针的指向变成null,导致程序出现诡异行为,故而已被弃用
编译时的提示
image.png
运行结果
image.png

std::unique_ptr

用来替代autu_ptr。
默认情况下,unique_ptr与裸指针有着相同的大小,对于大多数操作执行几乎相同的命令,性能接近裸指针。
unique_ptr不可复制,是个只移型别。
unique_ptr可以自定义删除器。
unique_ptr可以方便高效地转化为shared_ptr。

  1. class Base {};
  2. unique_ptr<Base> f() {
  3. return unique_ptr<Base>(new Base);
  4. }
  5. int main()
  6. {
  7. auto pbd = [](Base* b) {
  8. cout << "delete b" << endl;
  9. delete b;
  10. };
  11. unique_ptr<Base, decltype(pbd)> upb(new Base, pbd);
  12. shared_ptr<Base> spb = f();
  13. return 0;
  14. }

std::shared_ptr

shared_ptr采用引用计数来进行垃圾收集。
shared_ptr有另一个指针指向一块堆上的内存,保存了包括引用计数、自定义删除器等数据,故shared_ptr的大小是裸指针的2倍。
shared_ptr指定删除器不需要给定模板参数
shared_ptr<Base> spb(new Base, pbd);
image.png
将this指针传递给shared_ptr有坑,解决办法可以看《Effective Modern c++》
unique_ptr 可以指涉到数组,shared_ptr不能指涉数组,但都不如vector和array。

  1. #include <iostream>
  2. #include <memory>
  3. using namespace std;
  4. class T {
  5. private:
  6. static int id;
  7. int tid;
  8. public:
  9. T() {
  10. tid = id++;
  11. cout << "id = " << tid << " constructor called" << endl;
  12. }
  13. ~T() {
  14. cout << "id = " << tid << " destructor called" << endl;
  15. }
  16. };
  17. int T::id = 1;
  18. int main() {
  19. cout << "--------begin-----------" << endl;
  20. {
  21. cout << 1 << endl;
  22. shared_ptr<T> t1(new T);
  23. cout << 2 << endl;
  24. shared_ptr<T> t2(new T);
  25. cout << 3 << endl;
  26. shared_ptr<T> t3 = t1;
  27. cout << 4 << endl;
  28. if (!t1.get()) {
  29. cout << "t1 is null" << endl;
  30. }
  31. cout << 5 << endl;
  32. t2 = t1; // t2改变指向,会销毁id=2的对象
  33. cout << 6 << endl;
  34. }
  35. cout << "--------end-----------" << endl;
  36. return 0;
  37. }

运行结果
image.png

std::weak_ptr

可以指向一块由shared_ptr指向的内存,但是不参与引用计数。
可以用weak_ptr来创建shared_ptr。

  1. shared_ptr<Base> spb(new Base);
  2. weak_ptr<Base> wpb(spb);
  3. shared_ptr<Base> spb2 = wpb.lock();
  4. shared_ptr<Base> spb3(wpb);

若wpb已经悬空(失效),则创建出的spb为空。

std::make_shared

优先选用make_shared,而不是new T作为shared_ptr的初始参数。
make系函数不能自定义析构器。
make_shared会进行一些优化将控制块和对象内存分配到一起。
使用new指针初始化shared_ptr会有2次内存分配(1次对象,1次控制块),当引用计数为0时,对象内存释放,当弱计数(用于weak_ptr)为0时,控制块内存释放。
使用make函数初始化shared_ptr会将2者分配到一个内存块,只有一次内存申请,但是引用计数为0并不会释放内存块,必须等到弱计数为0时才会释放。