CPP 智能指针总结分享

发布于:2022-07-24 ⋅ 阅读:(467) ⋅ 点赞:(0)

Table of Contents

  1. 智能指针 - smart pointer
  2. 疑问暂存
  3. 作用
  4. shared_ptr
    1. 常用函数
      1. 构造 shared_ptr
      2. 谨慎使用原始指针
      3. 指定删除器
      4. 注意问题
  5. unique_ptr
  6. weak_ptr
    1. 解决的问题
    2. 设计目的
    3. 使用函数

智能指针 - smart pointer

智能指针用来确保一个对象可在没有引用后被删除。

疑问暂存

  1. 为什么感觉和 rust 的 copy,move 语义很像; cpp-vs-rust-ownership

  2. 当 shared_ptr ref_count 计数到 0 开始调用析构的行为,与 GC 的对比

    https://stackoverflow.com/questions/4663385/garbage-collection-vs-shared-pointers

    最主要的区别在与资源被释放的时间;

    • GC 可能发生在资源紧缺时,并且会要求程序暂停
    • shared pointers 紧跟在 reference count 缩减到 0 时发生
  3. GC 一定是存在于语言 runtime 上吗?

作用

  1. 防止内存泄漏:无需手动释放,可自动释放堆上内存
  2. 共享所有权指针的传播和释放,比如多线程使用同一个对象时析构问题

C++11 支持如下三种智能指针:shared_ptr,unique_ptr, weak_ptr,其中三者特点体现在所有权问题上。

shared_ptr

https://en.cppreference.com/w/cpp/memory/shared_ptr

img

shared_ptr 包含有两部分:

  1. 指向堆上对象的裸指针,raw_ptr
  2. 指向控制块,其中包含一个 reference count、一个 weak count

常用函数

  1. std::make_shared 创建对象 T,并由 std::shared_ptr 封装起来
  2. std::shared_ptr::get 返回存储的指针,
  3. std::shared_ptr::reset 重置管理的对象
  4. std::shared_ptr::use_count returns the number of shared_ptr objects referring to the same managed object
    Returns the number of different shared_ptr instances (this included) managing the current object. If there is no managed object, ​0​ is returned.
    返回 shared_ptr 的强引用计数
  5. std::shared_ptr::unique 若 use_count() 为 1 则返回 true,否则 false
#include <iostream>
#include <memory>

void fun(std::shared_ptr<int> sp) {
  std::cout << "in fun(): sp.use_count() == " << sp.use_count() << " (object @ "
			<< sp << ")\n";
}

int main() {
  auto sp1 = std::make_shared<int>(5);
  std::cout << "in main(): sp1.use_count() == " << sp1.use_count()
			<< " (object @ " << sp1 << ")\n";

  fun(sp1);

  std::cout << "in main() after fun call: sp1.use_count() == " << sp1.use_count()
			<< " (object @ " << sp1 << ")\n";
}

#+RESULTS:
| in | main(): | sp1.use_count() | == | 1 | (object | @ | 0x6000035c9158) | | | |
| in | fun(): | sp.use_count() | == | 2 | (object | @ | 0x6000035c9158) | | | |
| in | main() | after | fun | call: | sp1.use_count() | == | 1 | (object | @ | 0x6000035c9158) |

构造 shared_ptr

优先使用 make_shared 来构造,而无法将原始指针直接赋值,或者通过 reset 方式进行初始化:

audo sp1 = std:make_shared<int>;
sp1.reset(new int(666));
std::cout << "in main() after reset: sp.get() == " << sp1.use_count()
	<< sp1.get() << "  " << *sp1.get() << "\n";

谨慎使用原始指针

myPointer = new int;
delete myPointer; //freed memory
myPointer = NULL; //pointed dangling ptr to NULL

指定删除器

当用 shared_ptr 管理非 new 对象,或者无析构函数的类时,应为其传入 deleter

#include <iostream>
#include <memory>
using namespace std;

void DeleteIntPtr(int * p) {
  cout << "Call DeleteIntPtr" << endl;
  delete p;
}

int main()
{
  std::shared_ptr<int> p(new int(1), Deleteintptr);
  return 0;
}

注意问题

  1. 不要用一个原始指针初始化多个 shared_ptr

  2. 不要在函数实参中创建 shared_ptr
    可能会因实参的求值顺序而导致错误,一般情况下是从右到左

    function(shared_ptr<int>(new int), g());
    
  3. 避免循环引用
    循环引用会导致内存泄漏

#include <iostream>
#include <memory>

using namespace std;

class A;
class B;

class A {
public:
  std::shared_ptr<B> bptr;
  ~A() { cout << "A is deleted" << endl; }
};

class B {
public:
  std::shared_ptr<A> aptr;
  ~B() { cout << "B is deleted" << endl; }
};

int main()
{
  {
	std::shared_ptr<A> ap(new A);
	std::shared_ptr<B> bp(new B);

	ap->bptr = bp;
	bp->aptr = ap;
  } // ap, bp 离开了作用域名

  cout << "ap and bp died" << endl;
  return 0;
}

unique_ptr

https://en.cppreference.com/w/cpp/memory/unique_ptr
std::unique_ptr is a smart pointer that owns and manages another object through a pointer and disposes of that object when the unique_ptr goes out of scope.

The object is disposed of, using the associated deleter when either of the following happens:

the managing unique_ptr object is destroyed
the managing unique_ptr object is assigned another pointer via operator= or reset().

There are two versions of std::unique_ptr:

Manages a single object (e.g. allocated with new)
Manages a dynamically-allocated array of objects (e.g. allocated with new[])

独占对象的智能指针

  • 独占类型的智能指针,不能将其赋值给另一个 unique_ptr
  • unique_ptr 可以指向一个数组
  • unique_ptr 需要确定删除器的类型

当通过 move 转移给其他 unique_ptr 后,旧智能指针不再拥有原指针所有权了

如果只希望有一个智能指针管理资源或管理数组则使用 unique_ptr;
如果希望有多个智能指针管理同一个资源就用 shared_ptr;

weak_ptr

https://en.cppreference.com/w/cpp/memory/weak_ptr

解决的问题

当两个对象互相使用 shared_ptr 成员变量指向对方时,造成的循环引用会使引用计数失效,从而
导致内存泄漏;

weak_ptr 是一种 不控制对象生命周期 的智能指针:

  • 它指向一个 shared_ptr 所管理的对象
  • 强引用的 shared_ptr 保持对该对象寿命周期的控制
  • weak_ptr 只是提供了对管理对象的一个访问手段

设计目的

引入一种协助 shared_ptr 工作的智能指针,它只可以从一个 shared_ptr 或另一个
weak_ptr 对象构造,它的构造和析构不会引起引用计数的增加或减少

使用函数

  • lock:创建一个 shared_ptr 对象来管理引用对象
  • expired: 判断引用对象资源是否已经释放
#include <iostream>
#include <memory>

using namespace std;

std::weak_ptr<int> gw;

void observe()
{
  cout << "gw.use_count() == " << gw.use_count() << endl;
  if (shared_ptr<int> spt = gw.lock()) {
	cout << "*spt == " << *spt << endl;
  }
  else {
	cout << "gw is expired\n";
  }
}

int main()
{
  {
	auto sp = make_shared<int>(42);
	gw = sp;

	observe();
  }

  observe();
}

#+RESULTS:
| gw.use_count() | == | 1 |
| *spt | == | 42 |
| gw.use_count() | == | 0 |
| gw | is | expired |

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到