前言

本篇文章是 C++部分非常非常非常重要的一篇关于智能指针的讲解 , 同时内容也是面试考察的重点 ~

真正的重点在下篇 ~ 因为笔者要控制篇幅 , 所以只好分开了.

本节详细代码库 : 点击可跳转

本节文档 : CPlusPlus.com


一、什么是智能指针 ?

介绍

智能指针是C++中用于管理动态分配内存的高级工具,它通过封装普通指针并利用RAII(Resource Acquisition Is Initialization,资源获取即初始化)技术,确保在对象生命周期结束时自动释放内存,从而避免内存泄漏和其他资源管理错误。‌

智能指针最重要的特点是可以帮我们管理资源的释放 , 不需要我们管理了 .
同时智能指针可以像指针一样 , 拥有普通指针的功能 .

在这里插入图片描述


为什么要有智能指针呢 ?

C++中也有指针的存在 ,为什么还要设计智能指针出来呢 ? 这里就与异常部分有关了 .

  在异常机制中 , throw 会抛出异常 ,然而抛出异常后 , throw 后面的代码就不会去执行了 , 就会跳转到 try - catch 语句去捕获异常信息 .

struct Ptr
{
	Ptr() {}
	~Ptr() {cout << "~Ptr()" << endl;}
	int* _ptr = nullptr;
};


//演示代码
double Division(const int a , const int b)
{

	Ptr* ptr1 = new Ptr();
	Ptr* ptr2 = new Ptr();

	// a / b
	if (b == 0)
		throw(string("Division Zero Error !"));
	
	//调用 Ptr 的析构函数
	delete ptr1; 
	delete ptr2;

	return (double)a / b;

}

int main()
{
	int a = 0, b = 0;
	cin >> a >> b;

	try
	{
		cout << Division(a, b) << endl;;
	}
	catch (const string& str)
	{
		cout << str << endl;
	}
	catch (...)
	{
		cout << "Unknown Exception !" << endl;
	}

	return 0;
}

  在这里插入图片描述

那么针对这样的情况 , 想要内存不泄露 , 那我们还需要重新抛出异常来解决 , 这是不方便的 , 所以这里就提出了智能指针 , 很香 ~ ~ .

所以智能指针能很好的解决资源泄漏的问题 .


二、智能指针初见

前面也提到了 , 智能指针就是对普通指针的封装 , 可以像普通指针一样 , 准确来说 , 兼容指针功能 .

RAII 思想

  • 什么是 RAII ? (重要重要)

   RAII 即 : Resource Acquisition Is Initialization . 中文 : 资源获得立即初始化 .

本质 : 把资源拿来初始化 , 即 ; 对象得到资源 , 当对象生命周期结束时 , 进行析构把资源带走 , 这样就有效避免资源泄漏了 .


为什么智能指针可以有效避免资源泄漏呢 ?

这里具体分析一下 :

  • 实现一个简易的智能指针
//演示代码
template <class T>
class smart_ptr
{

public:
	//RAII 思想
	smart_ptr(T* ptr)
		:_ptr(ptr)
	{}

	~smart_ptr() 
	{ 
		delete _ptr;
		_ptr = nullptr;
		cout << "~smart_ptr()" << endl; 
	};

	//还要像普通指针一样 , 重载 * ->
	T& operator*()
	{
		return *_ptr;
	}

	T* operator->()
	{
		return _ptr;
	}

private:
	T* _ptr;
};


//演示代码
double Division(const int a, const int b)
{
	//这里 new 的底层是 operator new , 底层是 malloc , 返回是还是指针
	//所以可以用智能指针接受
	smart_ptr<int> ptr1(new int(1));
	smart_ptr<int> ptr2(new int(2));

	// a / b
	if (b == 0)
		throw(string("Division Zero Error !"));

	return (double)a / b;
}


int main()
{
	int a = 0, b = 0;
	cin >> a >> b;

	try
	{
		cout << Division(a, b) << endl;;
	}
	catch (const string& str)
	{
		cout << str << endl;
	}
	catch (...)
	{
		cout << "Unknown Exception !" << endl;
	}
	return 0;
}

  在这里插入图片描述
以上就可以体现出智能指针的用处了 , 很好用 , 不需要我们去手动去释放了 , 交给对象自动管理 .


总结智能指针的设计思路

  在这里插入图片描述


三、深剖智能指针

C++标准库中的智能指针 .

点击可跳转 !
  在这里插入图片描述


智能指针拷贝问题

智能指针的设计思想 RAII , 这个思想是让智能指针去代管资源 , 从而当对象生命周期结束时 , 去释放这块资源 , 但这样就没有问题吗 ?

在这里插入图片描述

所以就出来了标准库中的各种智能指针 , 这些指针的历史笔者就不探讨了 , 有兴趣的可以自行查看 !


各类智能指针介绍

1. 为什么会有各类智能指针 ? (重要)

以上笔者也展示了标准库中的各类指针指针 , 那么为什么会有这么多呢 ? 这同时也是常考题目

auto_ptr / shared_ptr / unique_ptr 它们的本质都是为了解决智能指针拷贝的问题 , 它们底层解决拷贝问题的思路和方式不同 , 所以会有这几个智能指针 .


2. auto_ptr

直接前提结论 : 不使用它 ! 不使用它 ! 不使用它 !

  • 语法

  在这里插入图片描述

  • 重要理解

在这里插入图片描述
可以发现 auto_ptr 的设计很危险 , 当管理权转移了以后 , 对象被悬空了 , 我们可能不知道再去访问程序就报错了 !


2. unique_ptr (重要重要)

这个智能指针是 C++11 提出的 , 那么这个就很有必要了 .

  • 语法

  在这里插入图片描述

  • 重要重要重要理解

在这里插入图片描述

需要详细代码看代码仓 ~~~~~~~~~~

#include <memory>
struct Ptr
{
	//强制默认构造
	Ptr() = default;

	Ptr(int* ptr)
		:_ptr(ptr)
	{}

	~Ptr() { delete _ptr; _ptr = nullptr; cout << "~Ptr()" << endl; }
	
	int* _ptr = nullptr;
	int _a = 1;
};


// unique_ptr 和 auto_ptr
void Test01()
{
	//不支持这样写 , 因为增加了 explicit 修饰 , 即不支持隐式类型转换
	//auto_ptr<Ptr> ptr = new Ptr(); // err
	int* ptr = new int(1);
	auto_ptr<Ptr> ptr1(new Ptr(ptr)); // ok 构造
	auto_ptr<Ptr> ptr2(ptr1); // ok 拷贝构造
	//这里可以通过调试看到 ptr1 被悬空了 , 很危险 !!!!

	//增加了 explicit 修饰, 即不支持隐式类型转换
	//unique_ptr<Ptr> ptr3 = new Ptr(); // err

	
	//ptr3 和 arr 是同一块资源
	unique_ptr<Ptr> ptr3(new Ptr(ptr)); // ok

	//不支持拷贝
	//unique_ptr<Ptr> ptr4(ptr3); // err
}

所以 , 当我们不需要拷贝时 , 用 unique_ptr 就很香了 ~


3. shared_ptr (极其极其重要)

  在这里插入图片描述

  • 语法

在这里插入图片描述

  • 使用
#include <memory>
struct Ptr
{
	//强制默认构造
	Ptr() = default;

	Ptr(int* ptr)
		:_ptr(ptr)
	{}

	~Ptr() 
	{ 
		delete _ptr; 
		_ptr = nullptr; 
		cout << "~Ptr()" << endl; 
	}
	int* _ptr = nullptr;
};

//shared_ptr 使用
void Test02()
{
	//template <class U> explicit shared_ptr (U* p);

	//不支持隐式类型转换
	//shared_ptr<Ptr> ptr1 = new Ptr(); // err
	
	//RAII
	int* ptr = new int(1);
	shared_ptr<Ptr> ptr1(new Ptr(ptr));  // ok
	//支持拷贝
	shared_ptr<Ptr> ptr2(ptr1);  // ok
	//调试可看出 , ptr / ptr1 / ptr2 都指向的同一块资源 , 并且只析构了一次
}

四、模拟底层实现(面试考)

模拟实现部分是面试重要考察点 , 需要我们手撕代码 ~~~~~~~~

本节笔者放入下篇讲解 , 因为这里还涉及的内容很多 , 为了控制篇幅 , 这里希望学者移至下篇敬请查看 !!!
  在这里插入图片描述

五、智能指针基础总结

在这里插入图片描述


总结

以上是对智能指针部分的介绍 , 重点还在下篇 , 请移步 !!

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐