前沿:

在C++中没有垃圾回收,所谓的垃圾回收就是指我们动态申请的资源,我们需要手动地进行释放,就比如:new了一个对象后,我们需要手动的释放,但是有时候,虽然我们进行了手动的释放,但是在delete之前遇到了异常,此时需要抛出异常,异常抛出之后,throw后面的语句不再执行,这就会导致我们申请的空间没有得到释放,从而导致内存泄露,这是很危险的,所以我们要借助智能指针来帮助我们自动的释放动态申请的资源~~~

一、智能指针的使用场景分析

代码语言:javascript

AI代码解释

double Divide(int a, int b)
{
	// 当b == 0时抛出异常 
	if (b == 0)
	{
		throw "Divide by zero condition!";
	}
	else
	{
		return (double)a / (double)b;
	}
}
void Func()
{
	// 这⾥可以看到如果发⽣除0错误抛出异常,另外下⾯的array和array2没有得到释放。 
	// 所以这⾥捕获异常后并不处理异常,异常还是交给外⾯处理,这⾥捕获了再重新抛出去。 
	// 但是如果array2new的时候抛异常呢,就还需要套⼀层捕获释放逻辑,这⾥更好解决⽅案 
	// 是智能指针,否则代码太戳了 
	int* array1 = new int[10];
	int* array2 = new int[10]; // 抛异常呢 
	try
	{
		int len, time;
		cin >> len >> time;
		cout << Divide(len, time) << endl;
	}
	catch (...)
	{
		cout << "delete []" << array1 << endl;
		cout << "delete []" << array2 << endl;
		delete[] array1;
		delete[] array2;
		throw; // 异常重新抛出,捕获到什么抛出什么 
	}
	// ...
	cout << "delete []" << array1 << endl;
	delete[] array1;
	cout << "delete []" << array2 << endl;
	delete[] array2;
}
int main()
{
	try
	{
		Func();
	}
	catch (const char* errmsg)
	{
		cout << errmsg << endl;
	}
	catch (const exception& e)
	{
		cout << e.what() << endl;
	}
	catch (...)
	{
		cout << "未知异常" << endl;
	}
	return 0;
}

从上面的程序中我们可以看到,new了以后,我们也delete了,但是因为抛异常就导致后面的delete没有得到执行,所以就导致内存泄露了,所以我们需要new以后捕获异常,捕获到异常后delete资源,再把异常抛出来,但是因为new本省也可能抛异常,连续的两个new和下面的Divide都有可能会抛出异常,这就让我们处理起来很麻烦。

但是,如果我们将智能指针放到这种场景中就会让问题变得很简单~~~

ok,那接下来,让我们一探智能指针的庐山真面目~~~

在学习智能指针之前,我们先来了解一下智能指针的设计思路(面试中也会被问的哦)

二、RAII和智能指针的设计思路

RAII是Resource Acquisition Is Initialization的缩写(请求资源立即初始化)

他是一种管理资源的类的设计思想,本质是一种利用对象生命周期来管理获取到的动态资源,从而避免资源泄露这里的资源可以是内存、文件指针、网络连接、互斥锁等),也就是说:需要手动申请,需要手动释放的东西都可以通过RAII设计的东西来管理。

RAII在获取资源的时候把资源委托给一个对象,接着通过这个对象来控制对资源的访问,资源在对象的生命周期内始终保持有效,最后在对象析构的时候对资源进行释放,这样就保证了资源的正常释放,从而避免资源泄露的问题!

有点不太明白!

简单来说就是:

我们获取资源的时候别自己管,初始化就是构造,立即构造给一个对象,委托给一个对象,交给这个对象进行管理。

为什么交给一个对象进行管理就没问题呢?

因为对象的释放是自动的,这个对象只要正常释放就一定会析构,只要我们在这个对象的析构函数里面对动态申请的资源进行释放,这样我们就可以避免资源泄露的问题

ok,我们通过代码来看一下——

代码语言:javascript

AI代码解释

template<class T>
class SmartPtr
{
public:
	SmartPtr(T* ptr)
		:_ptr(ptr)
	{}
	~SmartPtr()
	{
		cout << "delete:" << _ptr << endl;
		delete _ptr;
	}
private:
	T* _ptr;//因为我们申请的资源都是放在一个指针里面的
};
int main()
{
	SmartPtr<int> sp1 = new int(2);
	return 0;
}

ok,那接下来,我们来看看怎么用这个来解决上面的问题:

代码语言:javascript

AI代码解释

template<class T>
class SmartPtr
{
public:
	SmartPtr(T* ptr)
		:_ptr(ptr)
	{}
	~SmartPtr()
	{
		cout << "delete:" << _ptr << endl;
		delete[] _ptr;
	}
private:
	T* _ptr;//因为我们申请的资源都是放在一个指针里面的
};
double Divide(int a, int b)
{
	// 当b == 0时抛出异常 
	if (b == 0)
	{
		throw "Divide by zero condition!";
	}
	else
	{
		return (double)a / (double)b;
	}
}
void Func()
{ 
	SmartPtr<int> sp1= new int[10];
	SmartPtr<int> sp2 = new int[10];

	int len, time;
	cin >> len >> time;
	cout << Divide(len, time) << endl;
}
int main()
{
	try
	{
		Func();
	}
	catch (const char* errmsg)
	{
		cout << errmsg << endl;
	}
	catch (const exception& e)
	{
		cout << e.what() << endl;
	}
	catch (...)
	{
		cout << "未知异常" << endl;
	}
	return 0;
}

ok,也就是说这里无论是抛异常还是不抛异常,我们的资源是交给对象管理的,对象都会正常析构,对象会析构就回去调析构函数,会去调析构函数就会去释放资源

注意:

这里的RAII != 智能指针,RAII还可以设计出其他的东西,比如:锁……

  • 智能指针类除了满足RAII的设计思路,还要方便进行资源的访问,所以智能指针类还会像迭代器一样,重载operator*/operator->/operator[ ] 等运算符,方便访问资源

代码语言:javascript

AI代码解释

template<class T>
class SmartPtr
{
public:
	SmartPtr(T* ptr)
		:_ptr(ptr)
	{}
	~SmartPtr()
	{
		cout << "delete:" << _ptr << endl;
		delete[] _ptr;
	}
	T& operator*()
	{
		return *_ptr;
	}
	T* operator->()
	{
		return _ptr;
	}
	T& operator[](size_t i)
	{
		return _ptr[i];
	}
private:
	T* _ptr;//因为我们申请的资源都是放在一个指针里面的
};
int main()
{
	SmartPtr<int> sp1 = new int[5] {1,2,3,4,5};
	SmartPtr<pair<string, int>> sp2 = new pair<string, int>[3] { { "string", 1 }, { "sort",2 }};

	cout << sp1[2] << endl;
	cout << *sp1 << endl;
	cout << sp2->first << endl;
	cout << sp2[1].first << endl;
	return 0;
}

运行一下——

那这时候,就有uu想问了,这个智能指针是需要我们自己手动写的吗?

ok,特殊情况下,如果库中没有,则需要我们自己写,但是一般情况下,我们用库中的即可——

三、C++标准库智能指针的使用

C++标准库中的智能指针都是在<memory>这个头文件下面,我们包含<memory>就可以使用了,库中的智能指针有好几种,除了weak_ptr之外,其余智能指针都符合RAII和像指针一样访问的行为


 

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐