enable_shared_from_this and objects on stack

Viewed 3396

Is there a way to prevent shared_from_this() call for a stack-allocated object ?

The enable_shared_from_this<> in the base classes list is a strong indicator for class user, but is there a way to enforce the correct usage ?

Example code:

class C : public enable_shared_from_this<C>
{
public:
  shared_ptr<C> method() { return shared_from_this(); }
};

void func()
{
  C c;
  shared_ptr<C> ptr = c.method(); // exception coming from shared_from_this()
}
2 Answers

I found the solution.

In Dune library they use stack-compatible enable_shared_from_this class template adaptation.

Check the original source code here or check my example with the quick copy&paste & cleanup of code:

#include <cstdio>
#include <cassert>
#include <memory>
#include <iostream>

template<class T>
struct null_deleter
{
    void operator() (T*) const {}
};
template<typename T>
inline std::shared_ptr<T> stackobject_to_shared_ptr(T & t)
{
    return std::shared_ptr<T>(&t, null_deleter<T>());
}

template<typename T, typename T2>
inline std::shared_ptr<T2> stackobject_to_shared_ptr(T & t)
{
    return std::shared_ptr<T2>(dynamic_cast<T2*>(&t), null_deleter<T2>());
}

template<typename T>
class stack_compatible_enable_shared_from_this
: public std::enable_shared_from_this<T>
{
public:
    std::shared_ptr<T> shared_from_this()
    {
        try
        {
            return std::enable_shared_from_this<T>::shared_from_this();
        }
        catch (std::bad_weak_ptr&)
        {
            _local_ptr = stackobject_to_shared_ptr(*static_cast<T*>(this));
            return _local_ptr;
        }
    }
    
    std::shared_ptr<const T> shared_from_this() const
    {
        try
        {
            return std::enable_shared_from_this<T>::shared_from_this();
        }
        catch (std::bad_weak_ptr&)
        {
            _local_ptr = stackobject_to_shared_ptr(*const_cast<T*>(static_cast<const T*>(this)));
            return _local_ptr;
        }
    }
    
private:
    
    mutable std::shared_ptr<T> _local_ptr;
};

struct MyObj : public stack_compatible_enable_shared_from_this<MyObj>{};

int main (int argc, char **argv) {
    //std::shared_ptr<MyObj> so = std::make_shared<MyObj>(6);
    MyObj o{};
    auto * so = &o;
    {
        auto l = std::weak_ptr<MyObj>(so->shared_from_this());
        auto shared = l.lock();
        if (shared) { } //use it
    }
}
Related