智能指针相关:enable_shared_from_this()在开发中的常见应用

类中使用shared_ptr()的问题

当我们先定义一个指针,然后再用这个指针构造两个智能指针

复制代码
int main()
{
  int* pt = new int();
  std::shared_ptr<int> p1(pt);
  std::shared_ptr<int> p2(pt);
  std::cout << "p1.use_count() = " << p1.use_count() << std::endl;
  std::cout << "p2.use_count() = " << p2.use_count() << std::endl;
  return 0;
}

运行后就会报错,显示的是pt指针被重复释放了

原因是p1和p2都以为自己是唯一独占pt的智能指针,不知道还有智能指针指向pt

所以输出后发现两个引用计数都是1

如果需要不报错,就得这样写
shared_ptr<int> p2 = p1

通过p1来定义p2,它们就知道pt有两个智能指针了,就不会报错。

再来看一个代码

复制代码
class client
{
public:
	~client()
	{
		std::cout << "~client()\n";
	}
};

int main()
{
	client* cp = new client();
	std::shared_ptr<client> csp1(cp);
	std::shared_ptr<client> csp2(cp);

	std::cout << "csp1.use_count: " << csp1.use_count() << std::endl;
	std::cout << "csp2.use_count: " << csp2.use_count() << std::endl;

	return 0;
}

这个报的一样的错,原理相同,问题是我们实际开发中,很多时候需要通过this指针来获取对象的内容

这个时候需要通过enable_shared_from_this来解决问题

enable_shared_from_this的使用

复制代码
class client : public std::enable_shared_from_this<client>
{
public:
	~client()
	{
		std::cout << "~client()\n";
	}

	std::shared_ptr<client> get_ptr()
	{
		return shared_from_this();
	}
};

int main()
{
	client* cp = new client();
	std::shared_ptr<client> csp1(cp);
	std::shared_ptr<client> csp2 = cp->get_ptr();

	std::cout << "csp1.use_count: " << csp1.use_count() << std::endl;
	std::cout << "csp2.use_count: " << csp2.use_count() << std::endl;

	return 0;
}

将代码改写成这样,先公有继承这个模板类。

这里需要注意,在你通过shared_from_this()返回一个类的shared_ptr时,该对象必须已经被一个shared_ptr所管理,所以你不能直接csp2 = cp->get_ptr(),要在此之前先有csp1(cp)

这样的话,借助shared_from_this(),可以使得该对象只要引用计数不为零,就任意获取它的一个shared_ptr。只要还有shared_ptr持有它,它就不会消亡。

实际开发中应用,以一个服务器demo举例

首先看下面一段代码

复制代码
struct client : std::enable_shared_from_this<client>
{
public:
	void start()
	{
		
	}
	//...其他函数
}

void start()
{
	std::shared_ptr<client> s = std::make_shared<client>();
	s->start();
}

int main()
{
	start();
	return 0;
}

这里用make_shared初始化了一个client的shared_ptr,make_shared会让对象和控制块可以安全地存储在连续的内存块中。它简化了内存管理,并提高了性能。但是不支持自己写删除器。

start是一个初始的函数,里面会稍后添加业务,下面我们写一个定时器。

复制代码
public:
	void start()
	{
		start_up();
	}
	
private:
	void start_up()
	{
		_timer.expires_from_now(std::chrono::seconds(10));
		_timer.async_wait(std::bind(&client::time_out, shared_from_this()));
	}

	void time_out()
	{
		start_up();
	}
private:
	boost::asio::steady_timer _timer;

在类里面这样设计定时器,当start()调用的时候,会调用start_up()函数设置一个定时器,并且注册time_out()这个回调函数。

此时start()函数调用结束了,临时变量s的智能指针也已经释放,但是,定时器内通过调用shared_from_this(),返回了一个s管理的对象的shared_ptr给async_wait里的回调time_out()中,s管理的对象并未消亡,直到运行完回调time_out(),它才会消亡,但是回调里面如果继续调用start_up()重新设定计时器,便又会返回一个该对象的shared_ptr()传入新注册的回调time_out()内,以此类推,只要计时器不关闭,永远不会消亡。

基于这一点,可以和读写搭配起来,灵活控制当前类在什么条件下保活,什么条件下析构。

相关推荐
zh_xuan3 小时前
c++ 单例模式
开发语言·c++·单例模式
利刃大大5 小时前
【在线五子棋对战】二、websocket && 服务器搭建
服务器·c++·websocket·网络协议·项目
喜欢吃燃面5 小时前
C++刷题:日期模拟(1)
c++·学习·算法
SHERlocked936 小时前
CPP 从 0 到 1 完成一个支持 future/promise 的 Windows 异步串口通信库
c++·算法·promise
虚拟之7 小时前
36、stringstream
c++
我很好我还能学7 小时前
【面试篇 9】c++生成可执行文件的四个步骤、悬挂指针、define和const区别、c++定义和声明、将引用作为返回值的好处、类的四个缺省函数
开发语言·c++
南岩亦凛汀8 小时前
在Linux下使用wxWidgets进行跨平台GUI开发
c++·跨平台·gui·开源框架·工程实战教程
曦月逸霜8 小时前
第34次CCF-CSP认证真题解析(目标300分做法)
数据结构·c++·算法
galaxy_strive8 小时前
绘制饼图详细过程
开发语言·c++·qt
Unpredictable22210 小时前
【VINS-Mono算法深度解析:边缘化策略、初始化与关键技术】
c++·笔记·算法·ubuntu·计算机视觉