一、shared_ptr

动态内存与智能指针

C++中对象的生存周期以后再谈。

除了静态内存和栈内存,每个程序还拥有内存池。这部分内存被称作自由空间(free store)或(heap)。程序用堆来存储动态分配的对象。

为了更容易地使用动态内存,新的标准库提供了两种智能指针(smart pointer)类型来管理动态对象。

智能指针的行为类似常规指针,重要的区别是它负责自动释放所指的对象。都定义在 memory 头文件中。

  1. shared_ptr 允许多个指针指向同一个对象;
  2. unique_ptr 则“独占”所指向的对象;
  3. 还有一种名为 weak_ptr 的伴随类,它是一种弱引用,指向 shared_ptr 所管理的对象。

1、是什么?

类似vector,智能指针也是模板。因此在创建一个智能指针的时候必须提供额外的信息——指针指向的类型。

shared_ptr<string> p1;     // shared_ptr, 可以指向 string
shared_ptr<list<int>> p2;  // shared_ptr, 可以指向 int 的 list

默认初始化的智能指针中保存着一个空指针。

smart 表现在什么地方?shared_ptr 模板中有一个counter,用来保存有多少个指针指向同一个对象。只有当这个counter为0的时候,shared_ptr 才会把之前申请的动态内存给释放掉。

每一个 shared_ptr 对象都有一个成员函数——析构函数,通过这个函数来完成销毁工作。shared_ptr 的析构函数会递减它所指向的对象的引用计数。如果引用计数变为0,shared_ptr 的析构函数就会销毁对象,并释放它占用的内存。

2、怎么用?

  • 如何声明一个shared_ptr 对象?
shared_ptr<string> p1;     // 空智能指针, 可以指向 string
  • 如何初始化一个shared_ptr 对象?如何对一个shared_ptr 对象进行赋值?

当进行拷贝或者赋值操作时,每个 shared_ptr 都会记录有多少个其他 shared_ptr 指向相同的对象。

// 指向一个值为 42 的 int 的shared_ptr
// make_shared<T>(args) 必须与 T 的某个构造函数相匹配
shared_ptr<int> p1 = make_shared<int>(42);

// 如果不传入任何参数,就会进行值初始化
shared_ptr<int> p2 = make_shared<int>();

// shared_ptr<T> p(q)     p 是 q 的拷贝,会递增 q 中的计数器
shared_ptr<int> p3(p1)   // p1 和 p3 指向相同的对象,此对象有两个引用者

// 还有一种初始化 shared_ptr 的方法
shared_ptr<int> p4 = new int(42); // 错误:必须使用直接初始化形式,使用了隐式转换,不能把正常指针隐式转换为shared_ptr
shared_ptr<int> p5(new int(43));  // 正确:使用直接初始化形式
// 思考为什么必须使用直接初始化形式??
  • 计数器

无论何时我们拷贝一个 shared_ptr,计数器都会递增

计数器递增的情况:当用一个shared_ptr 初始化另一个 shared_ptr,或将它作为参数传递给一个函数以及作为函数的返回值时;

计数器递减的情况:当我们给shared_ptr 赋予一个新值或是shared_ptr 被销毁(局部的shared_ptr 离开其作用域)。一旦一个shared_ptr 的计数器变为0,它就会自动释放自己所管理的资源。

auto r = make_shared<int>(42);  // r 指向的 int 只有一个引用者
r = q; // 给 r 赋值,令其指向另一个地址
        // 递增 q 指向的对象的引用计数
        // 递减 r 原来指向的对象的引用计数
        // r 原来指向的对象已没有引用者,会自动释放

注意:

1、shared_ptr 在无用之后忘记了销毁,程序仍会正确执行,这就造成了浪费内存。shared_ptr 在无用之后仍然保留的一种可能情况是,将shared_ptr 存放在一个容器中,随后重排了容器,从而不再需要某些元素。在这种情况下,应该确保使用erase 删除那些不再需要的shared_ptr 元素。

2、程序使用动态内存出于以下三种情况:

a、程序不知道自己需要使用多少对象;

b、程序不知道所需对象的准确类型;

c、程序需要在多个对象间共享数据。

容易出错的地方:

1、不要混合使用普通指针和智能指针;

2、不要使用get() 初始化另一个智能指针或为智能指针赋值;想想为什么?

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值