Reputation: 309
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
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