c++shared-ptrsmart-pointersenable-shared-from-this

When should we use std::enable_shared_from_this


I just knew std::enable_shared_from_this form this link.
But after reading the code below, I don't know when to use it.

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';    
    }

The code above is "not so good" because there is no existing shared_ptr before calling getptr(). So the good thing should be:

std::shared_ptr<Good> gp1 = std::make_shared<Good>(); // having a shared_ptr at the beginning
std::shared_ptr<Good> gp2 = gp1->getptr();

However, if I have already had a shared_ptr object, why don't I just simply code like this: std::shared_ptr<Good> gp2 = gp1;, meaning that I don't need std::enable_shared_from_this at all.

In my opinion, using std::enable_shared_from_this is to make sure that more than one shared_ptr objects have the same control block so that we can avoid the double-delete problem. But if I must remind myself to create a shared_ptr at the beginning, why don't I just remind myself to use shared_ptr object to create a new one, instead of using raw pointer?


Solution

  • The hint about when std::enable_shared_from_this<T> is useful is in its name: when yielding objects based on some requests it may be necessary to return a pointer to an object itself. If the result should be a std::shared_ptr<T> it becomes necessary to return such a pointer from within a member function where there is generally no std::shared_ptr<T> accessible.

    Having derived from std::enable_shared_from_this<T> provides a way to get hold of a std::shared_ptr<T> given just a pointer of type T. Doing so does, however, assume that the object is already managed via a std::shared_ptr<T> and it would create mayhem if the object is allocated on the stack:

    struct S: std::enable_shared_from_this<S> {
        std::shared_ptr<S> get_object() {
            return this->shared_from_this();
        };
    }
    
    int main() {
        std::shared_ptr<S> ptr1 = std::make_shared<S>();
        std::shared_ptr<S> ptr2 = ptr1->get_object();
        // ...
    }
    

    In a realistic scenario there is probably some condition under which a std::shared_ptr<T> to the current object is returned.