2

In his report on the Fall 2017 standards meeting, Herb Sutter has the following example of what the range-based for statement with initializer is simplifying:

{
  T thing = f();
  for (auto& x : thing.items()) {
    // Note: “for (auto& x : f().items())” is WRONG
    mutate(&x);
    log(x);
  }
}

Why is for (auto& x : f().items()) wrong? That is, when does f().items() yield undefined behavior but T thing = f(); ... thing.items() not yield it?

(This question might be considered a duplicate but the answer was only revealed by writing the question, not by normal search, so I decided it was worthwhile including in StackOverflow.)

Community
  • 1
  • 1
Eponymous
  • 6,143
  • 4
  • 43
  • 43

1 Answers1

3

If t.items() returns a reference to a member of t, then f().items() will give you a dangling reference and thus undefined behavior.

Breaking it down: f() will be a temporary that will be destroyed after the items() call returns. If items() returns a reference to a member of that temporary, it will become dangling once the temporary is destroyed.

See https://stackoverflow.com/a/40955021/309334 for more detail and a way of writing your methods so they won't have this problem.

Eponymous
  • 6,143
  • 4
  • 43
  • 43