I was trying Coverity out on some code base and I got a warning on a code akin to
struct Foo
{
std::string name;
};
Foo getFoo();
//...
const auto& name = getFoo().name;
useName(name);
Is this code valid?
I had the intuition that it's indeed invalid. But then, when searching for proofs, I've come across [class.temporary]/6.4, which seems to say that it's actually well-formed. Yet, Coverity issues a warning, and Coverity is surely written by some smart folks that can interpret the standard better than me.
The specific Coverity warning that's issued is
Dereferencing the returned or out-of-scope stack pointer will access an invalid location on the stack after its scope or after the function returns.
In whateverSurroundingFunction(): Pointer to a local stack variable returned or used outside scope (CWE-562)
on the subsequent usage of name
. The preceding warning is that
out_of_scope: Temporary variable of type
Foo
goes out of scope
And a sort of MRE is this (kudos to @user4581301 in the comments).
SO has a bunch of questions about temporary bound references, but those that I've seen each has a slightly different context, hence here comes yet another question on them.
This code is well-formed. As the linked standard says, the lifetime of the temporary returned by getFoo()
will be extended to the lifetime of the reference variable name
.
(emphasis mine)
Whenever a reference is bound to a temporary or to a subobject thereof, the lifetime of the temporary is extended to match the lifetime of the reference
The reference is bound to the subobject name
of the temporary Foo
directly, then the lifetime gets extended. Other ways, e.g. binding the reference via the member function returning reference to data member won't work.
struct Foo
{
std::string name;
std::string& get_name() { return name; }
};
Foo getFoo();
then
const auto& name = getFoo().get_name();
std::cout << name << std::endl; // UB; name is dangled