当前位置: 首页 > article >正文

c++-------------------智能指针

1.智能指针的使用和原理

1.1. 智能指针的使⽤场景分析

下面程序中我们使用了new了以后,我们也delete了,但是如果抛异常之之后,后面的delete就没有执行,内存就得不到释放就导致了内存泄漏,所以我们需要new以后捕获异常,捕获到异常后delete内存,再把异常抛 出,但是因为new本⾝也可能抛异常,连续的两个new和下⾯的Divide都可能会抛异常,让我们处理起 来很⿇烦。智能指针放到这样的场景⾥⾯就让问题简单多了。

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* arr1 = new int[10];
	int* arr2 = new int[10];// 抛异常呢
	try {

		int len, time;
		cin >> len >> time;
		cout << Divide(len, time) << endl;
	}
	catch (...)
	{
		cout << "delete []" << arr1 << endl;
		cout << "delete []" << arr2 << endl;
	}
	delete[]arr1;
	delete[]arr2;

	throw;

}


int main()
{
	try {
		Func();
	}
	catch (const char* errmsg)
	{
		cout << errmsg << endl;
	}
	catch (const exception& e)
	{
		cout << e.what() << endl;
	}
	catch (...)
	{
		cout << "未知异常" << endl;
	}


	return 0;
}

2.RAII和智能指针的设计思路

RAII是Resource Acquisition Is Initialization的缩写,他是⼀种管理资源的类的设计思想,本质是
⼀种利⽤对象⽣命周期来管理获取到的动态资源,避免资源泄漏,这⾥的资源可以是内存、⽂件指
针、⽹络连接、互斥锁等等。RAII在获取资源时把资源委托给⼀个对象,接着控制对资源的访问,
资源在对象的⽣命周期内始终保持有效,最后在对象析构的时候释放资源,这样保障了资源的正常
释放,避免资源泄漏问题。
智能指针类除了满⾜RAII的设计思路,还要⽅便资源的访问,所以智能指针类还会想迭代器类⼀
样,重载 operator*/operator->/operator[] 等运算符,⽅便访问资源。
template<class T>
class Smartptr {
public:
	Smartptr(T* ptr = nullptr)
		:_ptr(ptr)
	{}
	~Smartptr()
	{
		if (_ptr)
			delete _ptr;
	}
	T& operator*()
	{
		return *_ptr;
	}
	T* operator->()
	{
		return _ptr;
	}
private:
	T* _ptr;
};

void Func()
{
// 这⾥使⽤RAII的智能指针类管理new出来的数组以后,程序简单多了
SmartPtr<int> sp1 = new int[10];
SmartPtr<int> sp2 = new int[10];
for (size_t i = 0; i < 10; i++)
{
sp1[i] = sp2[i] = i;
}
int len, time;
cin >> len >> time;
cout << Divide(len, time) << endl;
}

3.. C++标准库智能指针的使⽤

C++标准库中的智能指针都在<memory>这个头⽂件下⾯,我们包含<memory>就可以是使⽤了,
智能指针有好⼏种,除了weak_ptr他们都符合RAII和像指针⼀样访问的⾏为,原理上⽽⾔主要是解
决智能指针拷⻉时的思路不同。
auto_ptr 是C++98时设计出来的智能指针,他的特点是拷⻉时把被拷⻉对象的资源的管理权转移给
拷⻉对象,这是⼀个⾮常糟糕的设计,因为他会到被拷⻉对象悬空,访问报错的问题,C++11设计
出新的智能指针后,强烈建议不要使⽤auto_ptr。其他C++11出来之前很多公司也是明令禁⽌使⽤
这个智能指针的。
unique_ptr 是C++11设计出来的智能指针,他的名字翻译出来是唯⼀指针,他的特点的不⽀持拷
⻉,只⽀持移动。如果不需要拷⻉的场景就⾮常建议使⽤他。
shared_ptr 是C++11设计出来的智能指针,他的名字翻译出来是共享指针,他的特点是⽀持拷⻉,
也⽀持移动。如果需要拷⻉的场景就需要使⽤他了。底层是⽤引⽤计数的⽅式实现的。
weak_ptr 是C++11设计出来的智能指针,他的名字翻译出来是弱指针,他完全不同于上⾯的智能指
针,他不⽀持RAII,也就意味着不能⽤它直接管理资源,weak_ptr的产⽣本质是要解决shared_ptr
的⼀个循环引⽤导致内存泄漏的问题。
我们来一个一个介绍分析
auto_ptr:
auto_ptr<Date>ap1(new Date);
auto_ptr<Date>ap2(ap1);

这个是支持拷贝得但是拷贝时,管理权限转移,ap1没有权限管理这个所以ap1是没办法访问Data里面得对象和改变里面对象得值得,一旦访问或改变就会报错

unique_ptr:

unique_ptr<Date>un1(new Date);
unique_ptr<Date>un2(move(un1));

这个是不支持拷贝得但是他支持移动但是在移动得时候跟auto_ptr是一样的,移动的时候un1会悬空所以要谨慎使用。

share_ptr:

shared_ptr<Date>sh1(new Date);
shared_ptr<Date>sh2(sh1);
shared_ptr<Date>sh3(sh2);

cout << sh1.use_count() << endl;

这个智能指针是支持拷贝的他里面会有一个use_count这个计数器指向一个就++释放一个就--等到为0的时候就说明没有人指向这块空间就给彻底释放了

// ⽀持移动,但是移动后sp1也悬空,所以使⽤移动要谨慎
shared_ptr<Date> sp4(move(sp1));

4.weak_ptr

weak_ptr不⽀持RAII,也不⽀持访问资源,所以我们看⽂档发现weak_ptr构造时不⽀持绑定到资
源,只⽀持绑定到shared_ptr,绑定到shared_ptr时,不增加shared_ptr的引⽤计数,那么就可以
解决上述的循环引⽤问题。
weak_ptr也没有重载operator*和operator->等,因为他不参与资源管理,那么如果他绑定的
shared_ptr已经释放了资源,那么他去访问资源就是很危险的。weak_ptr⽀持expired检查指向的
资源是否过期,use_count也可获取shared_ptr的引⽤计数,weak_ptr想访问资源时,可以调⽤
lock返回⼀个管理资源的shared_ptr,如果资源已经被释放,返回的shared_ptr是⼀个空对象,如
果资源没有释放,则通过返回的shared_ptr访问资源是安全的
int main()
{
std::shared_ptr<string> sp1(new string("111111"));
std::shared_ptr<string> sp2(sp1);
std::weak_ptr<string> wp = sp1;
cout << wp.expired() << endl;
cout << wp.use_count() << endl;
// sp1和sp2都指向了其他资源,则weak_ptr就过期了
sp1 = make_shared<string>("222222");
cout << wp.expired() << endl;
cout << wp.use_count() << endl;
sp2 = make_shared<string>("333333");
cout << wp.expired() << endl;
cout << wp.use_count() << endl;
wp = sp1;
//std::shared_ptr<string> sp3 = wp.lock();
auto sp3 = wp.lock();
cout << wp.expired() << endl;
cout << wp.use_count() << endl;
*sp3 += "###";
cout << *sp1 << endl;
return 0;
}


http://www.kler.cn/a/581793.html

相关文章:

  • 途游游戏25届AI算法岗内推
  • 2024华为OD机试真题-日志排序(C++)-E卷-100分
  • AttributeError: module ‘backend_interagg‘ has no attribute ‘FigureCanvas‘
  • Android Compose MutableInteractionSource介绍
  • 工程化与框架系列(28)--前端国际化实现
  • TDengine作为存储有什么缺点
  • 数据库之PostgreSQL详解(待补充)
  • Websocket的基本使用
  • 使用 React 和 Ant Design 处理 Excel 和 CSV 文件
  • upload-labs-master通关攻略(1~4)
  • 本地部署 OpenManus 保姆级教程(Windows 版)
  • C语言零基础入门教程(1)
  • 关于sqlalchemy的ORM的使用
  • R语言中byrow参数的作用
  • 【GIT】non-fast-forward错误
  • 大白话react第十九章React 与 WebGL 项目的深度拓展和优化
  • 计算机图形学交互式技术实验(鼠标、拾取操作和菜单)——绘制可用鼠标进行修改颜色的五角星和矩形
  • Linux rpcbind漏洞
  • Python----计算机视觉处理(Opencv:自适应二值化,取均值,加权求和(高斯定理))
  • GitHub 项目版本管理与 Release 发布流程记录