Search code examples
c++visual-c++shared-ptrmutableenable-shared-from-this

Why doesn't std::enable_shared_from_this use a mutable std::weak_ptr?


I understand that most std library implementations choose to implement std::enable_shared_from_this by storing a std::weak_ptr in the base class. This leads to the following:

#include <memory>

class Foo : public std::enable_shared_from_this<Foo>
{
public:
    std::shared_ptr<Foo> GetSharedBar() const
    {
        // returns shared_ptr<const Foo> instead of std::shared_ptr<Foo>
        return shared_from_this();
        // Error in VC++2019 due to mismatch.
    }
};

It seems clear to me that despite needing to update the reference count, shared_from_this() is not actually mutating the target object. This seems like an ideal use for mutable, so that shared_from_this() can be marked as const with respect to the derived object.

Why isn't it implemented with mutable?

To elucidate the answer below: it is implemented with the std::weak_ptr marked mutable, but that only allows the std::weak_ptr to be mutated, not for us to hand off a non-const to someone else.


Solution

  • These both fail to compile:

    class Foo : public std::enable_shared_from_this<Foo>
    {
    public:
        std::shared_ptr<Foo> GetSharedBar() const
        {
            // error: could not convert from 'shared_ptr<const Foo>' to 'shared_ptr<Foo>'
            return shared_from_this();
        }
    };
    
    class Bla
    {
    public:
        Bla* getThis() const
        {
            // error: invalid conversion from 'const Bla*' to 'Bla*'
            return this;
        }
    };
    

    But they both work if you remove const from the functions. The issue is that in a const member function, the this pointer is a const pointer.

    As another example, take this:

    class kluf
    {
        const std::string* k;
        std::string* getK() 
        {
            // error: invalid conversion from 'const string*' to 'std::string*'
            return k;
        }
    };
    

    Clearly you are not allowed to hand a const member off to somebody else in a non-const state. This also goes for the this pointer, and in a const function this is const.