Given the following code, where x
is a dangling const reference
to a vanished object, and is therefore undefined behavior.
auto get_vec() { return std::vector<int>{1,2,3,4,5}; }
const auto& x = get_vec().back();
It seems like neither GCC 7.3, Clang 6.0 and MSVC is able to emit a warning, even with all warnings enabled.
Does anyone know if it is any way to emit a warning in these cases?
Is there any difference between const auto&
and auto&&
in these cases?
Note, if back()
would return by value, it wouldn't be undefined behavior as the lifetime temporary object x is extended to function scoop.
Long story: I have a code base where const auto&
is used as the default way of initializing variables, and for some odd reason these cases executes correctly using MSVC, but when compiled with Clang for android, every occurance results in a wrongly assigned value. For now the solution seems to investigate every const auto&
in the whole code base.
Also, in many cases the const auto&
refers to a heavy object returned by reference so simply removing the &
is not a solution.
One more thing, I'm responsible for the miss use of const auto&
:)
Only thing I can come up with right now is to use CLANG with -fsanitize=address. But of course this will only help at runtime, but then you get something nice like this:
Maybe you have automated unit tests you can easily run as "sanizizer" builds.
Ouch. :(
UB is UB innit.
Yes.
Just as you cannot tell at a glance whether a particular case is "safe"/correct, the compiler cannot tell simply from a function signature.
If it always had access to the full definition of every function, it would be able to warn you in some cases (and analysis tools like
-fsanitize=address
will do their best with this), but there is no general-case solution for the compiler to detect dangling references at runtime.Also congratulations on the payrise you can receive now that the guilty employees (the author and the reviewer) have been fired, right? :)
Obviously, for the above example, one would write something like:
It does not make much sense to create a whole vector to keep only its last element. And if you have an expression like the above one and want to use a single expression, then you should almost never uses
auto &
to start with.It the object is large, then you should either use move semantic or reference counting. So maybe you would have a function like
GetLastValue
that would returns by value a copy of the last vector value and then move that into the target destination.You really need to understand what you are doing. Otherwise, you should use a language like C# where you need less knowledge about the internal working of the compiler or the exact language specifications.
As a general rule, I would say that you should not use
auto &
unless you are sure that you want a reference to the returned item. The most common case when I would useauto &
orconst auto &
would be for a range based loop. For example, with the above vector namedxx
, I would generally write:except if I know that it returns trivial types.
Almost certainly there is no way of warning on this. The compiler has no idea whether the referenced object returned by
back()
will outlive the line or not, and if it does, there's no problem (though I'd be hard pressed to think of a realistic situation where a non-static member function called on a temporary object returns a reference to an object which outlives the temporary object).It sounds like whoever wrote that code read about the most important const, and took away entirely the wrong lesson from it.