cxx std::enable_shared_from_this
六月 13, 2022 [c++] #c++cxx std::enable_shared_from_this
c++ std::enable_shared_from_this
在很多应用中,我们可能希望对象永远都存在,特别是在一些异步执行的程序中,回调函数的传入是需要保证对象指针的有效性的,所以,我们一般都是传入共享指针,我们就用到了std::enable_shared_from_this,这样可以通过成员函数返回该对象的共享指针,而不会出现多个共享指针管理相同对象的问题(如果你使用了std::shared_ptr<T>(this),那么,自然就会出现多个共享指针管理相同对象,这个是引入的根本原因)
当我们需要将对象的函数注册到其他异步执行的对象中时,我们在传入对象指针时,可以通过shared_from_this()函数返回该对象的共享指针,那么可以保证该对象不会在异步执行时就被释放,如下为c++ reference中的例子, Bad就是通过getptr()会返回多个共享指针管理相同的this指针,会出现重复释放问题
#include <memory>
#include <iostream>
struct Good: std::enable_shared_from_this<Good> // note: public inheritance
{
std::shared_ptr<Good> getptr() {
return shared_from_this();
}
};
struct Bad
{
std::shared_ptr<Bad> getptr() {
return std::shared_ptr<Bad>(this);
}
~Bad() { std::cout << "Bad::~Bad() called\n"; }
};
int main()
{
// Good: the two shared_ptr's share the same object
std::shared_ptr<Good> gp1 = std::make_shared<Good>();
std::shared_ptr<Good> gp2 = gp1->getptr();
std::cout << "gp2.use_count() = " << gp2.use_count() << '\n';
// Bad: shared_from_this is called without having std::shared_ptr owning the caller
try {
Good not_so_good;
std::shared_ptr<Good> gp1 = not_so_good.getptr();
} catch(std::bad_weak_ptr& e) {
// undefined behavior (until C++17) and std::bad_weak_ptr thrown (since C++17)
std::cout << e.what() << '\n';
}
// Bad, each shared_ptr thinks it's the only owner of the object
std::shared_ptr<Bad> bp1 = std::make_shared<Bad>();
std::shared_ptr<Bad> bp2 = bp1->getptr();
std::cout << "bp2.use_count() = " << bp2.use_count() << '\n';
}
同时,在使用这个函数之前,一定要已经创一个共享指针对象,并且,这个对象没有超过生命周期,测试代码如下
#include <iostream>
#include <memory>
#include <fstream>
#include <thread>
using namespace std;
// 对于普通类型指针
#define PTR(X) X* // 普通指针
#define CONST_PTR(X) const X* // 指针内容不可修改
#define PTR_CONST(X) X* const // 指针不可修改
#define CONST_PTR_CONST(X) const X* const // 指针和指针内容不可修改
// Ptr: 普通共享指针
// ConstPtr: 不可修改内容的共享指针
// PtrConst: 不可修改指针的共享指针,内容可以修改
// ConstPtrConst: 只能初始化的指针,不能做任何的修改动作
#define SHARED_PTR_DEFINE(X) \
public: \
typedef std::shared_ptr<X> Ptr; \
typedef std::shared_ptr<const X> ConstPtr; \
typedef const std::shared_ptr<X> PtrConst; \
typedef const std::shared_ptr<const X> ConstPtrConst;
typedef std::function<void()> CALLBACK;
class executeTestA
{
SHARED_PTR_DEFINE(executeTestA);
public:
executeTestA()
{
}
~executeTestA()
{
if(th.joinable())
{
th.join();
}
}
void start(const CALLBACK& cb)
{
this->callback = cb;
th = std::thread(&executeTestA::run, this);
}
public:
void run()
{
int count = 1;
while(true && count < 100)
{
if(callback != nullptr)
{
callback();
}
else
{
std::cout << "non call back" << std::endl;
}
std::this_thread::sleep_for(std::chrono::seconds(1));
count++;
}
std::cout << "run exit" << std::endl;
}
private:
CALLBACK callback;
std::thread th;
};
class testA : public std::enable_shared_from_this<testA>
{
SHARED_PTR_DEFINE(testA);
public:
testA() : std::enable_shared_from_this<testA>()
{
}
shared_ptr<testA> getSharedPtr()
{
return shared_from_this();
}
shared_ptr<const testA> getSharedPtr() const
{
return shared_from_this();
}
public:
void print()
{
std::cout << "testA ==> " << shared_from_this().use_count() << std::endl;
}
protected: // 或者 private:
testA(const testA& a)
{
}
testA& operator=(const testA& a)
{
}
};
class testB
{
testB(const testA::Ptr& a1) : a(a1)
{
}
private:
testA::Ptr a;
};
int main()
{
cout << "Hello World!" << endl;
testA::Ptr ptr(new testA()); // ok
// PTR(testA) ptr(new testA()); // error
// executeTestA::Ptr execute(new executeTestA);
// execute->start(std::bind(&testA::print, ptr));
// PTR(testA) ptr(new testA);
ptr->print();
// std::ofstream ofstr("/home/hsw/test.txt", std::ios_base::out | std::ios_base::binary);
// print(ofstr);
while(true)
{
std::this_thread::sleep_for(std::chrono::seconds(1));
}
return 0;
}