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
I realized that actually I did need these two recent members and the only thing I needed is to have:
template<typename T>
class Index {
public:
const std::string& text;
const std::vector<T>& index;
decltype(index.begin()) begin() const { return index.begin(); }
decltype(index.end()) end() const { return index.end(); }
};
This cover all the needs in the client code. So, I was just lucky trying const
as a type of returning value with the reference; as the result I got this warning and got understanding of it with help of all participants of the thread.
It's not a false positive, and you can reproduce it on Compiler Explorer if you instantiate the class template:
template class Index<int>;
MSVC gives you the warning you've already posted, and GCC gives you
<source>:10:72: warning: returning reference to temporary [-Wreturn-local-addr]
10 | const decltype(index.cbegin())& begin() const { return index.cbegin(); }
| ~~~~~~~~~~~~^~
The issue is that index.cbegin()
returns an iterator by value, not by reference.
The return type is const std::vector::const_iterator&
, and this const&
binds to a temporary const_iterator
object.
You've said that you're returning the iterator by const&
because
performance consideration for the cases when iterator size is big enough to have impact.
This 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.
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.