This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 114a. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.

2024-04-18


900. Lifetime of temporaries in range-based for

Section: 6.7.7  [class.temporary]     Status: C++23     Submitter: Thomas J. Gritzan     Date: 2009-05-12

[Accepted at the November, 2022 meeting as part of paper P2718R0.]

Temporaries created in the expression of the range-based for statement are not given special treatment, so they only persist to the end of the expression. This can lead to undefined behavior as __range and the iterators are used in the expansion of the statement. Such temporaries should have their lifetimes extended until the end of the statement.

Rationale (October, 2009):

In the expansion, expression is used to initialize a reference. If expression is a temporary, its lifetime is thus extended to that of the reference, which is the entire for statement.

Additional notes, February, 2017:

Posting from Daniel Frey to the std-discussion group:

Some people have tried

  namespace detail {
    template< class C > struct reverse_range {
      explicit reverse_range (C& _c) : c(_c) {}
      auto begin () { using std::rbegin; return rbegin(c); }
      auto end () { using std::rend; return rend(c); }
     private:
      C& c;
    };
  }


  template< class C > auto reverse (C& c) {
    return detail::reverse_range<C>{c};
  }

In an attempt to allow:

  // some function
  std::vector<int> foo();

  // correct usage
  auto v = foo();
  for( auto i : reverse(v) ) { std::cout << i << std::endl; }

  // problematic usage
  for( auto i : reverse(foo()) ) { std::cout << i << std::endl; }

The problem is that the temporary returned by foo() is destructed before the loop starts executing. [This issue] was supposed to be about that, but considers only the top-level temporary.

It might be reasonable to make the range-based for treat the for-range-initializer like a function argument: all temporaries of the expression should be destructed after the execution of the loop. This also removes the only place where binding a reference to a temporary extends its lifetime implicitly, unseen by the user.

Notes from the February, 2017 meeting:

CWG was inclined to accept the suggested change but felt that EWG involvement was necessary prior to such a decision.