enable_shared_from_this 是什么
std::enable_shared_from_this 是一个类模板,用来返回指向当前对象的shared_ptr智能指针。在说明它的作用前我们可以看一下如下代码:
demo.cpp
#include <memory>
#include <iostream>
class A
{
public:
A() { std::cout << "A()" << std::endl; }
~A() { std::cout << "~A()" << std::endl; }
std::shared_ptr<A> getSharedPtr()
{
std::shared_ptr<A> ptr(this);
return ptr;
}
};
int main()
{
std::shared_ptr<A> ptr1(new A());
std::shared_ptr<A> ptr2 = ptr1->getSharedPtr();
return 0;
}
类 A 中有一个函数 getSharedPtr() 函数,用来返回指向当前对象的一个shared智能打针。其实就是用 this 构造了一个智能指针进行返回,执行结果如下:
看着好像没什么问题,别着急,再看下一个例子:
class B
{
public:
B() {
m_age = new int(10);
std::cout << "B()" << std::endl;
}
~B() {
std::cout << "~B()" << std::endl;
if (m_age){
delete m_age;
m_age = nullptr;
}
}
std::shared_ptr<B> getSharedPtr()
{
std::shared_ptr<B> ptr(this);
return ptr;
}
private:
int* m_age;
};
int main()
{
std::shared_ptr<B> ptr1(new B());
std::shared_ptr<B> ptr2 = ptr1->getSharedPtr();
std::cout << ptr1.use_count() << std::endl; // 输出引用计数
std::cout << ptr2.use_count() << std::endl; // 输出引用计数
return 0;
}
与类A不同的是,类B有一个在堆上创建的成员,我们再来看一下运行结果:
可以看到程序再运行到最后时刻崩溃了,报错:free(): invalid pointer,free 了无效的指针。我们应该能看到是重复释放的问题,这里我们将裸指针赋给了智能指针,这样做潜在的危险就是对象被多次释放。
细心的小伙伴肯定看到了,智能指针ptr1 和 ptr2 的引用计数都是 1,在程序执行结束的时候都会释放一次资源,导致程序崩溃。enable_shread_from_this 的作用就是解决这个问题,示例代码如下:
class C: public std::enable_shared_from_this<C>
{
public:
C() {
m_age = new int(10);
std::cout << "C()" << std::endl;
}
~C() {
std::cout << "~C()" << std::endl;
if (m_age){
delete m_age;
m_age = nullptr;
}
}
std::shared_ptr<C> getSharedPtr()
{
return shared_from_this();
}
private:
int* m_age;
};
int main()
{
std::shared_ptr<C> ptr1(new C());
std::shared_ptr<C> ptr2 = ptr1->getSharedPtr();
std::cout << ptr1.use_count() << std::endl;
std::cout << ptr2.use_count() << std::endl;
return 0;
}
运行结果如下:
可以看到,此时两个智能指针的引用计数都为2,这两个智能指针指向了相同的资源。在 main 函数退出后,两个智能指针依次释放,引用计数依次减一,直至为0,资源成功释放。
推荐一个零声学院免费教程,个人觉得老师讲得不错,
分享给大家:[Linux,Nginx,ZeroMQ,MySQL,Redis,
fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,
TCP/IP,协程,DPDK等技术内容,点击立即学习: