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

2023-12-02


2257. Lifetime extension of references vs exceptions

Section: 6.7.7  [class.temporary]     Status: CD5     Submitter: Hubert Tong     Date: 2016-04-07

[Accepted as a DR at the February, 2019 meeting.]

There is implementation divergence on the following example:

  #include <stdio.h>
  struct A {
    bool live;
    A() : live(true) {
      static int cnt;
      if (cnt++ == 1) throw 0;
    }
    ~A() {
      fprintf(stderr, "live: %d\n", live);
      live = false;
    }
  };
  struct AA { A &&a0, &&a1; };
  void doit() {
    static AA aa = { A(), A() };
  }
  int main(void) {
    try {
      doit();
    }
    catch (...) {
      fprintf(stderr, "in catch\n");
      doit();
    }
  }

Some implementations produce

  in catch
  live: 1
  live: 1
  live: 0

While others produce

  live: 1
  in catch
  live: 1
  live: 1

With regard to the reference to which the first-constructed object of type A is bound, at what point should its lifetime end? Perhaps it should be specified that the lifetime of the temporary is only extended if said initialization does not exit via an exception (which means that calling ::std::exit(0) as opposed to throwing would not result in a call to ~A()).

See also issue 1634.

Notes from the December, 2016 teleconference:

The consensus was that the temporaries should be destroyed immediately if an exception occurs. 14.3 [except.ctor] paragraph 3 should be extended to apply to static initialization, so that even if a temporary is lifetime-extended (because it has static storage duration), it will be destroyed in case of an exception.

Proposed resolution (January, 2019):

Change 14.3 [except.ctor] paragraph 3 as follows:

If the initialization or destruction of an object other than by delegating constructor is terminated by an exception, the destructor is invoked for each of the object's direct subobjects and, for a complete object, virtual base class subobjects, whose initialization has completed (9.4 [dcl.init]) and whose destructor has not yet begun execution, except that in the case of destruction, the variant members of a union-like class are not destroyed. [Note: If such an object has a reference member that extends the lifetime of a temporary object, this ends the lifetime of the reference member, so the lifetime of the temporary object is effectively not extended.—end note] The subobjects are destroyed in the reverse order of the completion of their construction. Such destruction is sequenced before entering a handler of the function-try-block of the constructor or destructor, if any.