如何正确使用std :: shared_from_this或欺骗它?

时间:2017-01-18 10:33:35

标签: c++ memory-management

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();
}

4 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:1)

您应该从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()();
}

答案 2 :(得分:1)

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

但是,如果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>{});
}

正确的方法是this

#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 << "Destructed\n"; }
    std::shared_ptr<A> share()
    {
        return shared_from_this();
    }

    void operator()()
    {
        library_function(share());
    }
    void do_something() {
        std::cout << "do_something\n";
    }
};


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>{});
}

答案 3 :(得分:0)

您的课程应该来自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>();