目录
前言:
C++的智能指针是普通指针“升级版”,采用了面向对象的思想对普通指针进行了又一层封装,将原本是内置类型的普通指针封装成用户自己定义的一个类对象。智能指针存在的原因:普通指针在进行申请空间时,需要手动释放该指针,有些场景下用户可能来不及释放导致内存泄漏,而一个类对象在销毁时是一定会调用该对象的析构函数的。所以把释放指针的动作交给类的析构函数处理则指针所指向的空间一定会得到释放,这就是智能指针的核心思想。
1、内存泄漏
1.1 什么是内存泄漏
内存泄漏指的是程序员向系统动态申请一块空间,用完之后却没能将其释放掉,最后导致失去了对该空间控制,并且此时系统也无权利用该空间的资源,把这类情况叫做内存泄漏。
1.2 内存泄漏的危害
若一个程序长期运行并出现了内存泄漏,同样的程序却会让内存不断的消耗殆尽,并且使程序的运行越来越慢,最后当内存都泄漏完了程序就会卡死。
1.3 如何避免内存泄漏
1、养成良好的代码习惯,并且设计程序时严格遵守规范,但凡是申请的空间都记得释放。(但是若遇到了抛异常的情况,哪怕记得释放空间也会造成内存泄漏)
2、针对抛异常的情况,采用RAII思想或者智能指针来管理内存(下文细讲)。
3、使用内存泄漏工具来检测程序中是否有内存泄漏。
因此可以把上述的方法分为两种思路: 1、事先预防型、如上述的1、2点。2、事后查错型,上述的第3点。
2、智能指针的应用场景
有些场景下,哪怕程序员已经手动释放了空间,但是依然会造成内存泄漏,比如在进行抛异常时,会出现抛出的异常会连续结束好几个栈帧空间,直到被最外层的栈帧空间所捕获,若之前栈帧空间中还有一些指针没来得及释放该栈帧就结束了,就会造成内存泄漏。
示例代码如下:
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
void _func()
{
int a = -2;
if (a < 0)
throw string("a为负数发生错误");
}
void Func()
{
int* p1 = new int;
_func();//若_func函数抛异常,则p1会来不及释放,造成内存泄漏
delete p1;//虽然释放了p1,但仍然可能会造成内存泄漏
}
int main()
{
try
{
Func();
}
catch (string& e)
{
cout << e << endl;
}
return 0;
}
上述代码的具体示意图如下:

虽然上述代码的情况可以用重新抛出的问题解决,但是用智能指针的方式显然会更好,智能指针的大概思路是:将p1封装成一个类,再将delete p1写进该类的析构函数,这样一来当结束Func栈帧时p1也会被释放。
3、智能指针的原理
智能指针采用的是RAII的思想,只不过智能指针在此基础上增添了指针的行为,因此需要先了解RAII的具体思想。
3.1 RAII
RAII全称(Resource Acquisition Is Initialization),是利用对象的生命周期来控制程序资源,比如当一个对象的生命周期结束时,因为其析构函数是自动调用的,这时候就可以在该析构函数内实现对资源的管控,达到资源的“自动化”。
用上述代码来举例RAII思想,先构造一个对象,把p1指向的空间管理权也给到该对象,并且在该对象的析构函数内释放该空间,当该函数栈帧销毁时,该对象会自动的调用析构函数从而释放p1指向的空间,所以无需手动释放p1也不会造成内存泄漏。
将RAII思想转变为类的代码如下:
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
template<class T>
class RAII
{
public:
RAII(T* ptr = nullptr)
: _ptr(ptr)
{
cout << "RAII()" << endl;
}
~RAII()
{
cout << "~RAII()" &l

本文详细介绍了C++中内存泄漏的概念及其危害,探讨了智能指针如auto_ptr、unique_ptr和share_ptr的原理、应用场景,特别关注了循环引用和weak_ptr如何解决这一问题。通过实例展示了智能指针如何通过RAII思想自动管理内存,避免内存泄漏。
最低0.47元/天 解锁文章
1126

被折叠的 条评论
为什么被折叠?



