1 year ago

#206858

test-img

roystgnr

Can dereferencing a non-temporary iterator create a temporary?

With the following code:

typedef const int * const & RefType;
typedef std::vector<int *>::const_iterator IterType;

RefType reffunc (const IterType & it) { return *it; }

I find that g++ 10.3.0 and 11.2.0, as well as clang++ 11.0.1 and 13.0.0 are completely happy. But, g++ 9.4.0 warns me that I'm returning reference to temporary [-Wreturn-local-addr] and clang++ 9.0.1 warns me that I'm returning reference to local temporary object [-Wreturn-stack-address]. This doesn't appear to be an overzealous warning, either: I see segmentation faults in a more complicated code that appear to trace to an equivalent of the above line, and in the debugger, even though my iterator hasn't been destroyed or changed, the reference-to-pointer I got from it appears corrupted. Also, playing with code in Godbolt does seem to show the resulting assembly changing from versions 9-and-earlier to versions 10-and-later of each compiler (though I'm afraid I don't know assembly and can't understand the changes).

The problems here only triggered after I started trying to be more strict about constness. If I change const_iterator to iterator, and typedef int * & RefType? No problems. Even if I keep const_iterator and typedef int * const & RefType, no problems. Equivalent use cases were in our real code for many years, with no warnings or segfaults.

If I keep the const but return a pointer:

const int * const * ptrfunc (const IterType & it) { return &*it; }

Still no problems.

If I then turn the pointer into a reference:

RefType reffunc (const IterType & it) { return *ptrfunc(it); }

Still no problems!

So in one sense I've got a workaround here, an implementation of the same API that gives no warnings or segfaults (at least for the particular two compilers that were breaking before) ... but are those compilers actually broken? Am I really writing valid C++, but there was a bug in both g++-9 and clang++-9, and neither bug has been fixed? (even though g++ 9.4.0 postdates the fixes in g++ 10!?) Or am I invoking Undefined Behavior according to the C++ standard, and the clang/gcc warnings that used to catch it regressed, but my code might just break again when a user upgrades to a future compiler or chooses some different optimization options?

The only vaguely related thing I can find in C++ standards is Defect Report 198, but I don't see how it would apply here - the iterator I'm using in these codes is being passed by reference and isn't being destroyed before the reference obtained from it is used.

c++

temporary-objects

const-iterator

0 Answers

Your Answer

Accepted video resources