c++compiler-warningstemporary-objectsreference-binding

Is it false positive here: warning C4172: returning address of local variable or temporary?


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.


Solution

  • 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.

    Note on performance considerations

    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.

    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.