细谈C++智能指针

C++智能指针

提出的本意是内存泄漏的背景,不想手动去管理内存,交给一个类去管理,当类离开自身的作用域时会自动调用析构函数,释放已申请的内存。

auto_ptr

所有的智能指针类均被定义与头文件中
两个基本的初始化方式:

// 方式1
std::auto_ptr<int> sp1(new int(1));
// 方式2
std::auto_ptr<int> sp2;
sp2.reset(new int(1));

智能指针(smart pointer)sp1和sp2均持有一个在堆上分配的int对象,值都是1,这两块堆内存都在sp1和sp2释放时得到释放。
缺点:(被废弃的原因)
当复制一个auto_ptr对象时(拷贝构造或者拷贝赋值时),原auto_ptr对象所持有的堆内存对象也会被转移给复制出来的新的auto_ptr对象。
例如:

std::auto_ptr<int> sp1(new int(1));
std::auto_ptr<int> sp2(sp1);// 此时利用拷贝构造 sp1持有的堆对象被转移给sp2了
std::auto_ptr<int> sp3(new int(1));
std::auto_ptr<int> sp4;
sp4 = sp3;// 此时利用拷贝赋值 sp3持有的堆对象被转移给sp4了

unique_ptr

为了弥补上述auto_ptr的缺点,提出unique_ptr,这种sp对其持有的堆内存具有唯一的拥有权,也就是说该sp对资源的引用计数永远是1。
三个基本的初始化方式

// 方式1
std::unique_ptr<int> sp1(new int(2));
// 方式2
std::unique_ptr<int> sp2;
sp2.reset(new int(2));
// 方式3
std::unique_ptr<int> sp3 = std::make_unique<int>(2);// 推荐使用 更安全

当采用了以下unique_ptr核心源码后:

template<typename T, typename Deletor>
class unique_ptr
{
// 其他代码省略
public:
	// 移动构造函数
	unique_ptr(unique_ptr&& rhs) {
		this->m_pT = rhs.m_pT;
		// 源对象释放
		rhs.m_pT = nullptr;
	}
	// 移动赋值
	unique_ptr& operator=(unique_ptr&& rhs) {
		this->m_pT = rhs.m_pT;
		// 源对象释放
		rhs.m_pT = nullptr;
		return *this;
	}
	// 拷贝构造函数和赋值运算符被标记为delete
	unique_ptr(const unique_ptr&) = delete;
	unique_ptr& operator=(const unique_ptr&) = delete;
private:
	T* m_pT;

再测试

std::unique_ptr<int> sp1(std::make_unique<int>(3));
// 以下代码无法通过编译
std::unique_ptr<int> sp2(sp1); // 无法通过编译
std::unique_ptr<int> sp3;
sp3 = sp1; // 无法通过编译

// 以下可以通过编译且成功运行
std::unique_ptr<int> sp4(std::make_unique<int>(4));
std::unique_ptr<int> sp5(std::move(sp4));// 调用移动构造函数
std::unique_ptr<int> sp6;
sp6 = std::move(sp5);// 调用移动赋值函数

shared_ptr

与unique_ptr对其持有的资源具有独占性不同的是,shared_ptr持有的资源可以在多个shared_ptr之间共享,每多个shared_ptr对资源的引用,资源引用计数就会增加1,在每一个指向该资源的shared_ptr对象析构时,资源引用计数都会减少1,最后一个shared_ptr对象析构时,若发现资源引用计数为0,则将释放其持有的资源。
三个基本的初始化方式

// 方式1
std::shared_ptr<int> sp1(new int(5));
// 方式2
std::shared_ptr<int> sp2;
sp2.reset(new int(5));
// 方式3
std::shared_ptr<int> sp3;
sp3 = std::make_shared<int>(5);// 推荐使用

可以使用use_count()方法来获取当前管理的资源的引用计数,使用reset()方法来释放对当前管理的资源的引用。

weak_ptr

weak_ptr是一个不控制资源生命周期的智能指针,是对对象的一种弱引用,只提供了对其管理的资源的一个访问手段,引入它的目的是协助share_ptr工作。
weak_ptr可以从一个shared_ptr或另一个weak_ptr对象构造,shared_ptr可以直接赋值给weak_ptr,也可以通过weak_ptr的lock函数来获得shared_ptr。weak_ptr的构造和析构不会引起引用计数的增加或减少,可用来解决shared_ptr相互引用时的死锁问题。
因为无论通过哪种方式来创建weak_ptr,都不会增加资源的引用计数,所以当我们用weak_ptr来引用资源时,需要采用expired方法来检测引用的资源是否有效,方法返回true说明其引用的资源已失效,返回false说明该资源仍然有效。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值