项目中enable_shared_from_this的使用

开发板推荐:天空星STM32F407VET6开发板

超高性价比 STM32主控 | 超高主频 | 一板兼容百芯 | 比赛神器 | 沉金彩色丝印

目录

 

问题背景

shared_ptr的double free问题

一个类的内部异步使用this问题

enable_shared_from_this

注意事项


问题背景

         异步编程中对象声的声明周期需要一定的保证,通常对于一些异步的回调和lambda表达式等,均可以使用shared_ptr延长对象的声明周期,从而避免异步调用时对象指针悬空问题。但是对于一些必须在类的内部返回一个shared_ptr的情况,直接调用shared_ptr(*this)会存在double free的问题;因此需要借助enable_shared_from_this。

shared_ptr的double free问题

        若直接从原生指针分别构造shared_ptr则,则会引起多个智能指针单独控制同一个对象,在指针生命周期结束时,多个智能指针触发多次对象析构,可能导致程序崩溃。

        以下是一个典型的会引起double free 的代码示例:

void test_shared_ptr()
{
	PveProcess*p = new PveProcess;
	std::shared_ptr<PveProcess> p1(p);
	//std::shared_ptr<PveProcess> p2(p);
	//std::cout << p1.use_count() << std::endl;// 1
	//p1 和 p2两个智能指针均从同一个原生指针p构建,有各自独立的管控单元,析构时会析构两次导致未定义行为
	std::shared_ptr<PveProcess>p3(p1);
	std::shared_ptr<PveProcess>p4 = p3;
	std::cout << p1.use_count() << std::endl;//3 从智能指针自身拷贝构造或复值拷贝不会引起单独管控问题
}

         在类的外部,只要规规矩矩的使用智能指针的拷贝构造和赋值构造,避免原生指针的乱用基本不会造成double free问题,同时可以在异步编程中延长对象的声明周期;但是在类的内部,则不尽然。

一个类的内部异步使用this问题

#include<QtConcurrent>
class ProcessPveOut
{
public:
	void requestOut()
	{  
		QtConcurrent::run(&m_threadPool, [this]() {
			//一个耗时的网络处理
		});

		//_this 从原生指针this生成 该对象会引起double free问题
		auto _this = std::shared_ptr<ProcessPveOut>(this);
		QtConcurrent::run(&m_threadPool, [_this]() {
			//一个耗时的网络处理
		});
	}
	//...

private:
	QThreadPool m_threadPool;
};

        在使用该对象时,在超出ptr的作用域时,类内部第一种在异步表达式里面传递this指针的行为会造成指针悬空;第二种shared_ptr原本是要延长对象的声明周期,但是由于从原生指针this构造,会导致与ptr各自独立控制对象,引起double free问题。 

{
//出场处理
	{
		auto ptr = std::shared_ptr<ProcessPveOut>(new ProcessPveOut);
		ptr->requestOut(); //在ptr超出作用域时对象析构,但是requestOut可能未完成 this指针失效出问题
	}
    //... notify LED等后续操作
}

enable_shared_from_this

        enable_shared_from_this 是个CRTP模板类,提供了一个可以返回一个shared_ptr的接口。简单来说,就是可以在类成员函数内部,返回一个共管当前对象的shared_ptr对象以此来重写上面的业务代码即可解决以上问题。

#include<QtConcurrent>
class ProcessPveOut :public std::enable_shared_from_this<ProcessPveOut>
{
public:
	void requestOut()
	{  
		auto _this = shared_from_this();
		QtConcurrent::run(&m_threadPool, [_this]() {
			//一个耗时的网络处理
		});
	}
	//...

private:
	QThreadPool m_threadPool;
};

注意事项


        只允许在先前已被std::shared_ptr 管理的对象上调用 shared_from_this 。否则调用行为未定义 (C++17 前)抛出 std::bad_weak_ptr异常。这取决于std::enable_shared_from_this 的实现。std::enable_shared_from_this是在内部保存一个对 this 的弱引用(例如 std::weak_ptr)。当 std::shared_ptr 的构造函数检测到无歧义且可访问的 enable_shared_from_this 基类时,如果内部存储的弱引用未被生存的 std::shared_ptr 占有,就会赋值新建的 std::shared_ptr。

        避免在构造函数或析构函数中使用 shared_from_this:在这些阶段使用 shared_from_this 可能不安全,因为对象可能尚未完全构造或已经开始析构。

        避免使用 std::shared_ptr(this),这会绕过已有的引用计数管理,导致内存管理异常。

开发板推荐:天空星STM32F407VET6开发板

超高性价比 STM32主控 | 超高主频 | 一板兼容百芯 | 比赛神器 | 沉金彩色丝印

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值