lundi 25 mai 2015

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

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.

Aucun commentaire:

Enregistrer un commentaire