如何正确使用 std::shared_from_this 或绕过它

How to properly use std::shared_from_this or trick around it?

本文关键字:this from shared 何正确 std      更新时间:2023-10-16

给C++专家的问题:我有一个期望shared_ptr<T>的库函数,我想在T内调用这个函数。我知道share_from_this是正确的方法,但我无法理解它(以及如何正确使用它)。

我想出了一个技巧,我想知道它是否安全(没有 UB)。如果不是,你能解释一下如何在我的情况下使用share_from_this吗?

#include <memory>
template<class T>
void library_function(std::shared_ptr<T>)
{}
struct A {
    std::shared_ptr<A> share()
    {
        return std::shared_ptr<A>(this, [](A*){});
    }
    void operator()()
    {
        library_function(share());
    }
};

int main()
{
    A a;
    a();
}

首先,你想要share_from_this的对象需要是之前共享的对象,并由 std::shared_ptr 管理。确保允许它的类需要从std::enable_shared_from_this<A>公开继承。接下来,如果要从中创建共享指针,则需要使用方法 shared_from_this()

使用您当前的代码,它是安全的。

但是,如果library_function存储shared_ptr以后使用,并且a由于超出范围而被销毁。这是未定义的行为。那就不安全了。此示例代码与您的代码没有太大区别,但它在第二次调用中具有未定义的行为:

template<class T>
void library_function(std::shared_ptr<T> t)
{
    static std::shared_ptr<T> s;
    if (!s) {
        s = t;
    }
    if (s) s->do_something();
}
struct A {
    std::shared_ptr<A> share()
    {
        return std::shared_ptr<A>(this, [](A*){});
    }
    void operator()()
    {
        library_function(share());
    }
    void do_something() {
    }
};

int main()
{
    // This emulates some function call and go out of scope
    {
        A a;
        a();
    }
    // This call is undefined behavior
    library_function(std::shared_ptr<A>{});
}

正确的方法是这样的:

#include <memory>
#include <iostream>
template<class T>
void library_function(std::shared_ptr<T> t)
{
    static std::shared_ptr<T> s;
    if (!s) {
        s = t;
    }
    if (s) s->do_something();
}
struct A : std::enable_shared_from_this<A> {
    ~A() {std::cout << "Destructedn"; }
    std::shared_ptr<A> share()
    {
        return shared_from_this();
    }
    void operator()()
    {
        library_function(share());
    }
    void do_something() {
        std::cout << "do_somethingn";
    }
};

int main()
{
    // This emulates some function call and go out of scope
    {
        std::shared_ptr<A> a = std::make_shared<A>();
        (*a)();
    }
    library_function(std::shared_ptr<A>{});
}

你应该从 std::enable_shared_from_this 派生你的类。确保您的对象由 std::shared_ptr 管理。

#include <memory>
template<class T>
void library_function(std::shared_ptr<T>)
{}
struct A : public std::enable_shared_from_this<A> {
    void operator()()
    {
        library_function(shared_from_this());
    }
};

int main()
{
    auto a = std::make_shared<A>();
    a->operator()();
}

你的类应该派生自 std::enable_shared_from_this<> ,然后你可以调用this->shared_from_this()来获取它的shared_ptr<>

例如:

class foo : std::enable_shared_from_this<foo> {
public:
   void bar() {
      call_some_func(this->shared_from_this());
   }
};

因此,call_some_func()将收到指向foo实例的共享指针。这将起作用,因为原始实例已经在共享指针中,即实例创建为:

auto foo_inst = std::make_shared<foo>();