Search code examples
c++c++11shared-ptrsmart-pointersenable-shared-from-this

Question about the usage of shared_from_this() in practice


The below code snippet is seen at cppreference.

I am curious about what the intention of Best::getptr() is? When should I use this method in practice? Maybe a simple demo code helps a lot.

struct Best : std::enable_shared_from_this<Best> // note: public inheritance
{
    std::shared_ptr<Best> getptr() {
        return shared_from_this();
    }
    // No public constructor, only a factory function,
    // so there's no way to have getptr return nullptr.
    [[nodiscard]] static std::shared_ptr<Best> create() {
        // Not using std::make_shared<Best> because the c'tor is private.
        return std::shared_ptr<Best>(new Best());
    }
private:
    Best() = default;
};

I wrote a simple code snippet to use shared_from_this(), but I still can't see anything meaningful.

If I want to create a new instance, I just call Foo::Create(). If I have not called Foo::Create, Foo::getPtr() is meaningless (i.e. it could not be invoked at all) since there is no valid instance yet.

If I miss something, please let me know.

#include <iostream>
#include <memory>
 
class Foo : public std::enable_shared_from_this<Foo> {
private:     //the user should not construct an instance through the constructor below.                    
    Foo(int num):num_(num) { std::cout << "Foo::Foo\n"; }

public:
    ~Foo() { std::cout << "Foo::~Foo\n"; } 

    int DoSth(){std::cout << "hello world" << std::endl; return 0;}

    std::shared_ptr<Foo> getPtr() { return shared_from_this();}

    static std::shared_ptr<Foo> Create() {
        Foo* foo = new Foo(5);
        return std::shared_ptr<Foo>(foo);
    }

private:
    int num_;

};

int main()
{
    auto sp = Foo::Create();
    sp->DoSth();

    Foo& foo = *sp.get();
    auto sp1 = foo.getPtr();
    std::cout << sp.use_count() << std::endl;
}

Solution

  • shared_from_this() is intended to be used from within the shared class itself (hence its name), not so much by an external entity, which can always have access to a shared_ptr to that class.

    For example, you can have a class Database that hands out Views, which have to keep a back-pointer to the Database:

    struct View;
    
    struct Database : enable_shared_from_this<Database>
    {
        auto GetView() { return make_unique<View>(shared_from_this()); }
    };
    
    struct View
    {
        shared_ptr<Database> db;
        View(shared_ptr<Database> db) : db(move(db)) {}
    };