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


2756. Completion of initialization by delegating constructor

Section: 11.9  [class.init]     Status: review     Submitter: Brian Bi     Date: 2023-06-20

Subclause 6.7.3 [basic.life] paragraph 1 specifies:

... The lifetime of an object of type T begins when: except that ...

It is unclear whether initialization is considered complete when the (ultimate) target constructor completes, or when the outermost delegating constructor completes. Subclause 14.3 [except.ctor] paragraph 4 suggests it is the former:

If the compound-statement of the function-body of a delegating constructor for an object exits via an exception, the object's destructor is invoked. ...

Proposed resolution (approved by CWG 2023-07-14) [SUPERSEDED]:

  1. Split and change 11.9.3 [class.base.init] paragraph 9 as follows:

    [Note 3: An abstract class ... -- end note ] An attempt to initialize more than one non-static data member of a union renders the program ill-formed. [Note 4: After the call to a constructor for class X ... -- end note ] [Example 6: ... -- end example ]

    An attempt to initialize more than one non-static data member of a union renders the program ill-formed.

    An object's initialization is considered complete when a non-delegating constructor for that object returns. [Note: Therefore, an object's lifetime can begin (6.7.3 [basic.life]) before all delegating constructors have completed. -- end note]

  2. Change in 6.7.3 [basic.life] bullet 1.2 as follows:

    ... The lifetime of an object of type T begins when:
    • storage with the proper alignment and size for type T is obtained, and
    • its initialization (if any) is complete (including vacuous initialization) (9.4 [dcl.init], 11.9.3 [class.base.init]),
    except that ...

CWG 2023-10-20

Utterances about "during construction or destruction" in 11.9.5 [class.cdtor] need to be adjusted.

Possible resolution:

  1. Split and change 11.9.3 [class.base.init] paragraph 9 as follows:

    [Note 3: An abstract class ... -- end note ] An attempt to initialize more than one non-static data member of a union renders the program ill-formed. [Note 4: After the call to a constructor for class X ... -- end note ] [Example 6: ... -- end example ]

    An attempt to initialize more than one non-static data member of a union renders the program ill-formed.

    An object's initialization is considered complete when a non-delegating constructor for that object returns. [Note: Therefore, an object's lifetime can begin (6.7.3 [basic.life]) before all delegating constructors have completed. -- end note]

  2. Change in 6.7.3 [basic.life] bullet 1.2 as follows:

    ... The lifetime of an object of type T begins when:
    • storage with the proper alignment and size for type T is obtained, and
    • its initialization (if any) is complete (including vacuous initialization) (9.4 [dcl.init], 11.9.3 [class.base.init]),
    except that ...
  3. Change in 11.9.5 [class.cdtor] paragraph 2 as follows:

    During the construction initialization of an object, if the value of the object or any of its subobjects is accessed through a glvalue that is not obtained, directly or indirectly, from the constructor's this pointer, the value of the object or subobject thus obtained is unspecified.
  4. Change in 11.9.5 [class.cdtor] paragraph 4 as follows:

    Member functions, including virtual functions (11.7.3 [class.virtual]), can be called during construction or destruction (11.9.3 [class.base.init]). When a virtual function is called directly or indirectly from a constructor or from a destructor, including during the construction initialization or destruction of the class's non-static data members, and the object to which the call applies is the object (call it x) under construction or destruction being initialized or destroyed, the function called is the final overrider in the constructor's or destructor's class and not one overriding it in a more-derived class. If the virtual function call uses an explicit class member access (7.6.1.5 [expr.ref]) and the object expression refers to the complete object of x or one of that object's base class subobjects but not x or one of its base class subobjects, the behavior is undefined.
  5. Change in 11.9.5 [class.cdtor] paragraph 5 as follows:

    The typeid operator (7.6.1.8 [expr.typeid]) can be used during construction or destruction (11.9.3 [class.base.init]). When typeid is used in a constructor (including the mem-initializer or default member initializer (11.4 [class.mem]) for a non-static data member) or in a destructor, or used in a function called (directly or indirectly) from a constructor or destructor, if the operand of typeid refers to the object under construction or destruction being initialized or destroyed, typeid yields the std::type_info object representing the constructor or destructor's class. If the operand of typeid refers to the object under construction or destruction being initialized or destroyed and the static type of the operand is neither the constructor or destructor's class nor one of its bases, the behavior is undefined.
  6. Change in 11.9.5 [class.cdtor] paragraph 6 as follows:

    dynamic_casts (7.6.1.7 [expr.dynamic.cast]) can be used during construction or destruction (11.9.3 [class.base.init]). When a dynamic_cast is used in a constructor (including the mem-initializer or default member initializer for a non-static data member) or in a destructor, or used in a function called (directly or indirectly) from a constructor or destructor, if the operand of the dynamic_cast refers to the object under construction or destruction being initialized or destroyed, this object is considered to be a most derived object that has the type of the constructor or destructor's class. If the operand of the dynamic_cast refers to the object under construction or destruction being initialized or destroyed and the static type of the operand is not a pointer to or object of the constructor or destructor's own class or one of its bases, the dynamic_cast results in undefined behavior.