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

2024-11-11


2886. Temporaries and trivial potentially-throwing special member functions

Section: 6.7.7  [class.temporary]     Status: DR     Submitter: Jiang An     Date: 2024-04-27

[Accepted as a DR at the June, 2024 meeting.]

(From submission #531.)

Paper P1286R2 (Contra CWG DR1778) allowed trivial potentially-throwing special member functions. Whether such a trivial special member function is actually invoked is thus observable via the noexcept operator. Issue 2820 clarified the situation for value-initialization and removed a special case for a trivial default constructor.

Subclause 6.7.7 [class.temporary] paragraph 4 appears to normatively avoid invoking a trivial constructor or destructor, something best left to the as-if rule. There is implementation divergence for this example:

  struct C {
    C() = default;
    ~C() noexcept(false) = default;
  };

  static_assert(noexcept(C()));

A related question arises from the introduction of temporaries for function parameters and return values in 6.7.7 [class.temporary] paragraph 3. However, this situation can never result in actually throwing an exception during forward evolution: when the constructor becomes non-trivial, the permission to create a temporary object evaporates.

Proposed resolution (approved by CWG 2024-05-31):

  1. Change in 6.7.7 [class.temporary] paragraph 3 as follows:

    When an object of class type X is passed to or returned from a potentially-evaluated function call, if X has at least one eligible copy or move constructor (11.4.4 [special]), each such constructor is trivial, and the destructor of X is either trivial or deleted, implementations are permitted to create a temporary object to hold the function parameter or result object. The temporary object is constructed from the function argument or return value, respectively, and the function's parameter or return object is initialized as if by using the eligible trivial constructor to copy the temporary (even if that constructor is inaccessible or would not be selected by overload resolution to perform a copy or move of the object).
  2. Change in 6.7.7 [class.temporary] paragraph 4 as follows:

    When an implementation introduces a temporary object of a class that has a non-trivial constructor (11.4.5.2 [class.default.ctor], 11.4.5.3 [class.copy.ctor]), it shall ensure that a constructor is called for the temporary object. Similarly, the destructor shall be called for a temporary with a non-trivial destructor (11.4.7 [class.dtor]). Temporary objects are destroyed as the last step in evaluating the full-expression (6.9.1 [intro.execution]) that (lexically) contains the point where they were created. This is true even if that evaluation ends in throwing an exception. The value computations and side effects of destroying a temporary object are associated only with the full-expression, not with any specific subexpression.