In the following code:
#include <execution>
#include <vector>
template<typename T>
class Index {
public:
const std::string& text;
const std::vector<T>& index;
decltype(index.begin())& begin() { return index.begin(); } // No warning
decltype(index.end())& end() { return index.end(); } // No warning
const decltype(index.cbegin())& begin() const { return index.cbegin(); }
const decltype(index.cend())& end() const { return index.cend(); }
};
int main()
{
}
Visual Studio 2022 (recent version) gives warnings:
warning C4172: returning address of local variable or temporary
twice for every line with decltype
. At the same time godbolt with the same configuration doesn’t.
Is this false-positive warnings or the code should be fixed?
My intention in the code to return const reference to const iterators. Is this correct approach/syntax for this?
Update
Interesting thing that for non-const version (just added to the source code above) none of compilers give a warning, although we still have the same reference to local copy.
Update 2
As a second thought, is there a way to return not iterators, but the begin
/end
functions themselves to make it even more transparent?
2
Answers
You’re not returning the thing you have by reference, you’re returning the results of a function call.
That the function happens to be on a method you have a reference to is irrelevant.
It’s not a false positive, and you can reproduce it on Compiler Explorer if you instantiate the class template:
MSVC gives you the warning you’ve already posted, and GCC gives you
The issue is that
index.cbegin()
returns an iterator by value, not by reference.The return type is
const std::vector::const_iterator&
, and thisconst&
binds to a temporaryconst_iterator
object.Note on performance considerations
You’ve said that you’re returning the iterator by
const&
becauseThis is not something you should worry about.
Iterators are a generalization of pointers ([iterator.requirements.general] p1) and are meant to be small, lightweight objects that can be passed around by value cheaply.
If an iterator is expensive to pass around, that’s a design issue with the iterator.
Note that standard library algorithms in
<algorithm>
also take iterators by value.Note on language evolution
If P2748: Disallow Binding a Returned Glvalue to a Temporary is accepted into the C++26 standard (and the consensus is overall favorable), then your code will be ill-formed.
In other words, it likely won’t even compile in C++26.