Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it safe to use a C++11 range-based for-loop with an rvalue range-init? [duplicate]

Tags:

c++

foreach

c++11

Suppose I have a function that returns a std::vector by value:

std::vector<int> buildVector(); 

It would seem natural to iterate over the result using a range-based for:

for (int i : buildVector()) {   // ... } 

Question: Is it safe to do so?

My reading of the standard (actually, draft n4431) suggests that it might not be, though I'm having a hard time believing that the committee failed to allow for this usage. I'm hoping that my reading is incorrect.

Section 6.5.4 defines the range-based for:

for ( for-range-declaration : expression ) statement 

with the following desugaring:

{   auto && __range = range-init;   for ( auto __begin = begin-expr,              __end = end-expr;         __begin != __end;         ++__begin ) {     for-range-declaration = *__begin;     statement   } } 

where range-init is just ( expression ), and at least for class types, begin-expr is either __range.begin() or begin(__range), etc.

In my buildVector example, I think the range-init produces a temporary, which the implementation is allowed to destroy immediately after the __range reference is bound. This would mean that the __range reference might already be dangling by the time begin-expr is evaluated.

Certainly, it should always be safe to write this:

std::vector<int> notATemporary = buildVector(); for (int i : notATemporary) {   // ... } 

But I'm hoping I don't have to add this to my list of gotchas.

like image 841
mbrcknl Avatar asked May 26 '15 01:05

mbrcknl


People also ask

Are range-based for loops faster?

Range-for is as fast as possible since it caches the end iterator[citationprovided], uses pre-increment and only dereferences the iterator once. Then, yes, range-for may be slightly faster, since it's also easier to write there's no reason not to use it (when appropriate).

How does range-based for loop work?

Range-based for loop in C++ Range-based for loop in C++ is added since C++ 11. It executes a for loop over a range. Used as a more readable equivalent to the traditional for loop operating over a range of values, such as all elements in a container.

How do range-based for loops work C++?

C++11 introduced the ranged for loop. This for loop is specifically used with collections such as arrays and vectors. Here, the ranged for loop iterates the array num from beginning to end. The int variable var stores the value of the array element in each iteration.


Video Answer


1 Answers

Yes, it's perfectly safe.

From [class.temporary]/4-5:

There are two contexts in which temporaries are destroyed at a different point than the end of the fullexpression. The first context is when a default constructor is called [...]

The second context is when a reference is bound to a temporary. The temporary to which the reference is bound or the temporary that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference except:

  • A temporary bound to a reference member in a constructor’s ctor-initializer [...]
  • A temporary bound to a reference parameter in a function call [...]
  • The lifetime of a temporary bound to the returned value in a function return statement [...]
  • A temporary bound to a reference in a new-initializer [...]

None of those exceptions apply. The temporary thus persists for the lifetime of the reference, __range, which is the entire loop.

like image 90
Barry Avatar answered Sep 29 '22 19:09

Barry