怎么new一个指针_智能指针这么厉害,能解决让C/C++程序员头疼的“指针问题”?...

“指针问题”

C语言中的指针语法是很多初学者的噩梦,但是由于指针能够便捷的管理内存,后进者C++并没有抛弃指针语法。不过,由于指针过于灵活,很容易为程序带来内存溢出、内存泄漏等问题,即使是经验老道的程序员也不敢说能够完全避免这些问题,所以C++提供了引用语法,以期解决指针带来的问题。

e45cb3d7e90587f56f71c7f8d850d2cb.png

C++提供了引用语法,以期解决指针带来的问题

可惜的是,近些年的实践证明C++是离不开指针(这一点我们以后再谈)的,因此早期C语言程序员使用指针面临的问题,C++程序员也不得不考虑。C++的语法比C语言的语法复杂得多,若是不能提供一种缓解“指针问题”的方案,那真的有些说不过去了,所以“智能指针”就被设计出来了。

本文将讨论C++11中的std::shared_ptr智能指针。

C++中的指针的一个典型用法就是管理一段内存。常规做法是通过类似于 malloc() 的内存管理函数,或者new关键字等方法分配一段内存,并且定义一个指针指向这块内存,之后便可通过指针访问这块内存。

不过一般来说,malloc() 或者new关键字分配的内存不会被系统自动回收,这意味着即使分配的内存不再被使用,但若是程序员不主动释放分配的内存,这块内存将永远不能再被别的逻辑使用,这就是所谓的“内存泄漏”。

d034f12425c9dd55f1e2f36d826e8b77.png

保证 new/malloc() 和 delete/free() 的配对使用不就好了吗

可能有读者会想,保证 new/malloc() 和 delete/free() 的配对使用不就好了吗?这有什么难的!的确,在简单的项目里比较容易保证C++程序不会发生“内存泄漏”,但若是项目稍稍复杂一些,可能要使用别人提供的接口函数,这时再去确定内存的生命周期就稍显麻烦了,特别是有的同事懒得写文档,而他的接口函数源代码不可得的情况下。

简而言之,C++中类C语言的普通指针管理内存的确有着不方便的地方——程序员必须非常清楚整个架构,才能知道某段已分配的内存是否仍在被使用中,进而确保安全的释放已经不再使用的内存,这并非易事。

std::shared_ptr<> 是什么?

std::shared_ptr<>是C++11标准中的智能指针类,它很聪明,能够知道自己管理的对象是否还有人使用,若是没有人再使用自己管理的对象,就会自动的删除该对象。所以,shared_ptr能够在最大程度上帮助C++程序员避免内存泄漏问题,也能够避免“悬空指针”的出现。

正如shared_ptr的字面含义,“shared”意味着共享,即不同的shared_ptr可以与同一个指针建立联系,其内部通过“引用计数机制”实现自动管理指针。

通常来说,每一个shared_ptr对象在其内部都管理两部分内容:

  1. shared_ptr 对象本身
  2. shared_ptr 对象管理的内容
5ebc32a7a0e62fd1ae30a7a80562379c.png

“引用计数机制”

“引用计数机制”

假设计划使用指针 p 指向一块分配的内存,现在使用C++的智能指针类 shared_ptr 自动管理这块内存。

  • 当 shared_ptr 类实例化一个对象与指针 p 绑定时,其内部的构造函数会将对应指针 p 的计数加 1。
  • 当 shared_ptr 对象完成自己的生命周期,它的析构函数会将指针 p 对应的计数减 1。

引用计数减少到 0,就意味着没有 shared_ptr 对象还与指针 p 管理的内存绑定,也即没有人再使用这块内存了,于是 shared_ptr 的析构函数调用“delete”方法释放这块内存。

创建一个shared_ptr对象

将一个裸指针绑定到 shared_ptr 对象上是简单的,例如:

std::shared_ptr p1(new int());

上面这行C++代码在堆上分配了两块内存,一块用于存储new出来的 int 值,一块用于存储 shared_ptr 对象本身。正如前面讨论的,shared_ptr 对象在其内部使用“引用计数”机制管理“new int()”,这里“计数”的初始值显然是 1,因为暂时只有一个 shared_ptr 对象指向“new int()”上。

C++智能指针类 shared_ptr 提供了成员函数 use_count() 用于检查实际的“计数值”,请参考稍后的实例。

51a64126dcccbc01b45e49a0f74cf242.png

怎样将指针“赋值”给shared_ptr?

怎样将指针“赋值”给shared_ptr?

因为 shared_ptr 类的构造函数是 Explicit 的,所以像下面这样的C++代码是非法的:

// 非法std::shared_ptr p1 = new int();

不过,除了前文提到的那样通过shared_ptr构造函数绑定指针,还有一种推荐的方法用于绑定指针:

std::shared_ptr p1 = std::make_shared();

std::make_shared执行了类似于 shared_ptr 构造函数类似的工作:在堆上分配两块内存,一块用于存储 int 值,一块用于存储 shared_ptr 对象本身。

“解绑”

现在我们知道了怎样将普通的裸指针与 shared_ptr 对象绑定,那么怎样才能“解绑”呢?使用 shared_ptr 类提供的 reset() 成员函数即可:

p1.reset();

reset() 函数会将绑定指针的计数减 1,如果计数减小到 0,那么它将删除绑定的指针。reset() 函数也可以接收一个参数,例如:

p1.reset(new int(32));

这种情况下,它将与一个新指针“new int(32)”绑定,因此内部的计数将重新变为 1。

如果想直接解绑 p1 绑定的指针,还可以使用 nullptr,例如:

p1 = nullptr;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值