C++中的智能指针

本文介绍了C++中智能指针的重要性,解释了RAII原则,详细讨论了auto_ptr、unique_ptr和shared_ptr的使用、原理及优缺点,特别是shared_ptr中的循环引用问题和解决方案。
摘要由CSDN通过智能技术生成

1.为什么要使用智能指针?

先来看一段代码,分析这段代码有没有内存上的错误?

#include <iostream>
using namespace std;
void _MergeSort(int* a, int left, int right, int* tmp)
{
   
	 if (left >= right) return;
	 int mid = left + ((right - left) >> 1);
 	// [left, mid]
 	// [mid+1, right]
 	_MergeSort(a, left, mid, tmp);
	_MergeSort(a, mid + 1, right, tmp);
	 int begin1 = left, end1 = mid;
	 int begin2 = mid + 1, end2 = right;
	 int index = left;
	 while (begin1 <= end1 && begin2 <= end2) {
   
		 if (a[begin1] < a[begin2])
			 tmp[index++] = a[begin1++];
		 else
			 tmp[index++] = a[begin2++];
	 }
	 while (begin1 <= end1)
			 tmp[index++] = a[begin1++];
	 while (begin2 <= end2)
			 tmp[index++] = a[begin2++];
	 memcpy(a + left, tmp + left, sizeof(int)*(right - left + 1));
}
void MergeSort(int* a, int n){
   
	 int* tmp = (int*)malloc(sizeof(int)*n);
	 _MergeSort(a, 0, n - 1, tmp);
 	// free(tmp);
}
int main()
{
   
	 int a[5] = {
    4, 5, 2, 3, 1 };
	 MergeSort(a, 5);
	 return 0;
}

上面的问题分析出来我们发现有以下两个问题:

  1. 我们malloc开辟出来的内存空间,在程序结束前没有进行释放,存在内存泄漏的问题;
  2. 如果在malloc和free之间如果存在抛异常,那么还是有内存泄漏,这种问题就叫异常安全。

类似于malloc这样的问题,还有比如我们使用new来开辟内存空间,在程序结束之前也必须使用delete来释放。但当一个程序中频繁的使用内存空间,你能保证自己每一个手动开辟的内存块都释放了吗?在delete之前,倘若程序因为异常跳转后,你还能保证内存被释放吗?为了解决这种因为遗忘或者异常处理而导致内存泄漏的问题,我们就要用智能指针。

2.智能指针的使用及其原理

2.1RAII

RAII(Resource Acquisition Is Initialization)是一种利用对象生命周期来控制程序资源(如内存、文件句柄、网络连接、互斥量等等)的简单技术。
在对象构造时获取资源,接着控制对资源的访问使之在对象的生命周期内始终保持有效,最后在对象析构的时候释放资源。 借此,我们实际上把管理一份资源的责任托管给了一个对象。 这种做法有两大好处:

  1. 不需要显式地释放资源。
  2. 采用这种方式,对象所需的资源在其生命期内始终保持有效。

使用RAII思想设计的SmartPtr类:

// 使用RAII思想设计的SmartPtr类
template<class T>
class SmartPtr 
{
   
public:
//构造对象时获取资源
 	SmartPtr(T* ptr = nullptr)
 	: _ptr(ptr){
   
	 }
//对象析构时释放资源
 	~SmartPtr(){
   
 		if(_ptr)
 		delete _ptr;
 	}
private:
	 T* _ptr;
};
void MergeSort(int* a, int n)
{
   
 	int* tmp = (int*)malloc(sizeof(int)*n);
	 SmartPtr<int> sp(tmp);
}

2.2智能指针的使用及原理

上述代码中的SmartPtr还不能称为智能指针,因为它还不具有指针的行为。指针可以解引用,也可以通过->去访问所指内存空间中的内容。因此AutoPtr类中还需要将*、->重载下,才能让其像指针一样去使用。

class SmartPtr 
{
   
public:
	 SmartPtr(T* ptr = nullptr)
 		: _ptr(ptr){
   
 		}
 	~SmartPtr(){
   
 		if(_ptr)
 		delete _ptr;
 		}
w
 	T& operator*() {
   return *_ptr;}
 	T* operator->() {
   return _ptr;}
private:
 	T* _ptr;
};

具体使用:

#include<iostream>
using namespace std;
template<class T>
class SmartPtr 
{
   
public:
    SmartPtr(T* ptr = nullptr)
        : _ptr(ptr){
   
    }
    ~SmartPtr(){
   
        if 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值