Assertion to enforce creation of object as shared_ptr?

238 Views Asked by At

When using std::shared_ptr it can often be useful to make use of std::enable_shared_from_this<T> so that you have access to the shared_from_this() function.

One requirement of using shared_from_this() is that all instances of the object are constructed using std::shared_ptr. While this is a perfectly fine requirement, it feels very difficult to enforce to future users of the class.

If I create an object:

class MyClass : public std::enable_shared_from_this<MyClass>
{
public:
    MyClass()
    {

    }

    void doAThing()
    {
        // something I need done asynchronously
    }

    void someFunction()
    {
        std::weak_ptr<MyClass> w (shared_from_this());

        // we need to use a lambda that is executed asynchronously and
        // so we pass the std::weak_ptr to it to check this object still exists it is executed
        std::function<void()> f = [w]()
        {
            if (! w.expired())
                w.lock()->doAThing();
        };


        callAsynchronously (f); // this function passes the lambda to some queue and executes it asynchronously
    }
};

and then someone - perhaps years later - uses this class without constructing it as a shared_ptr...

MyClass m;
m.someFunction();

then we get a runtime crash:

libc++abi.dylib: terminating with uncaught exception of type std::__1::bad_weak_ptr: bad_weak_ptr

To be clear, I understand the solution to this is:

std::shared_ptr<MyClass> m = std::make_shared<MyClass>();
m->someFunction();

(of course one would need to ensure that the shared_ptr existed long enough for the asynchronous callback to execute, but I'm ignoring that here).

My question is this - how can we add some kind of static assertion in the constructor of an object that inherits from std::enable_shared_from_this<T> so that any construction of that object not as a std::shared_ptr is picked up at compile time rather than run time?

1

There are 1 best solutions below

0
On

The following code with a create-function worked for me without exception.

#include <memory>

class X : public std::enable_shared_from_this<X> {
    private:
        X() = default;

    public:
        static std::shared_ptr<X> makeX() {
            return std::shared_ptr<X>(new X());
        }

        void doSth() {
            auto sharedPtr = shared_from_this();
            // do sth
        }
};

int main() {
    auto x = X::makeX();
    x->doSth();
}