• 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏吧

c++ std::enable_shared_from_this

互联网 diligentman 3天前 8次浏览

在很多应用中,我们可能希望对象永远都存在,特别是在一些异步执行的程序中,回调函数的传入是需要保证对象指针的有效性的,所以,我们一般都是传入共享指针,我们就用到了std::enable_shared_from_this,这样可以通过成员函数返回该对象的共享指针,而不会出现多个共享指针管理相同对象的问题(如果你使用了std::shared_ptr<T>(this),那么,自然就会出现多个共享指针管理相同对象,这个是引入的根本原因)

class testA : public std::enable_shared_from_this<testA>
{
    SHARED_PTR_DEFINE(testA);
public:
    void print()
    {
        std::cout << "testA ==> " << std::endl;
    }

protected: // 或者 private:
    testA(const testA& a)
    {

    }

    testA& operator=(const testA& a)
    {

    }
};

当我们需要将对象的函数注册到其他异步执行的对象中时,我们在传入对象指针时,可以通过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() calledn"; }
};
 
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;
}

 


程序员灯塔
转载请注明原文链接:https://www.wangt.cc/2020/11/c-stdenable_shared_from_this/
喜欢 (0)