CforLinux
CforLinux

Reputation: 309

error: returning reference to temporary [-Werror=return-local-addr]

I have some code that looks like this

class Interface
{};

class Contained;

class Container
{
public:
    Container() : m_contained(std::make_shared<Contained>(*this))
    {
    }
    
    std::shared_ptr<Interface> get_contained()
    {
        return std::static_pointer_cast<Interface>(m_contained);
    }
    
private:
    std::shared_ptr<Contained> m_contained;
};

class Contained final : public Interface
{
public:
    Contained(Container& container) : m_container(container)
    {
    }
    
private:
    Container& m_container;
};

I was asked to change get_contained to return a reference, so naively I thought to do

    std::shared_ptr<Interface>& get_contained()
    {
        return std::static_pointer_cast<Interface>(m_contained);
    }

and compilation failed on

error: cannot bind non-const lvalue reference of type 'std::shared_ptr&' to an rvalue of type 'std::shared_ptr'

so I added const

    const std::shared_ptr<Interface>& get_contained()
    {
        return std::static_pointer_cast<Interface>(m_contained);
    }

and now I fail on

error: returning reference to temporary [-Werror=return-local-addr]

I then tried several more "fixes"

class Container
{
public:
    Container()
    {
        m_contained = std::make_shared<Contained>(*this);
    }

    const std::shared_ptr<Interface>& get_contained()
    {
        return std::static_pointer_cast<Interface>(m_contained);
    }

private:
    std::shared_ptr<Contained> m_contained{};
};

and

class Container
{
public:
    Container()
    {
        m_contained.reset(new Contained(*this));
    }

    const std::shared_ptr<Interface>& get_contained()
    {
        return std::static_pointer_cast<Interface>(m_contained);
    }

private:
    std::shared_ptr<Contained> m_contained{};
};

and in desperation this

class Container
{
public:
    Container()
    {
        std::shared_ptr<Contained> ptr = std::make_shared<Contained>(*this);
        m_contained = ptr; // also with std::move, but same result
    }

    const std::shared_ptr<Interface>& get_contained()
    {
        return std::static_pointer_cast<Interface>(m_contained);
    }

private:
    std::shared_ptr<Contained> m_contained{};
};

All failed on the same issue, can't return lvalue reference to temporary. I don't understand how can a member of a class that is properly initialized be temporary

Upvotes: 1

Views: 81

Answers (1)

Maciej Polański
Maciej Polański

Reputation: 473

I do not think this can be solved this way, because while the pointer to the derived class is also a pointer to the base class (simplified), the shared_ptr that holds the derived class is in no way connected by inheritance to the shared_ptr that holds the base class.

So there is no way to cast one to the other, and any pseudo-cast actually creates a new copy, which is unfortunately temporary.

If I can suggest anything, the following solution might work:

void get_contained(std::shared_ptr<Interface>& retval)
{
    retval = std::static_pointer_cast<Interface>(m_contained);
}

https://godbolt.org/z/7MoTdxKE6

Upvotes: 0

Related Questions