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


2841. When do const objects start being const?

Section: 11.4.5.1  [class.ctor.general]     Status: open     Submitter: Tom Honermann     Date: 2023-12-14

Subclause 11.4.5.1 [class.ctor.general] paragraph 5 specifies:

A constructor can be invoked for a const, volatile or const volatile object. const and volatile semantics (9.2.9.2 [dcl.type.cv]) are not applied on an object under construction. They come into effect when the constructor for the most derived object (6.7.2 [intro.object]) ends.

This is referring to the "constructor ending", but 6.7.3 [basic.life] bullet 1.3 refers to "the initialization is complete". These two points in the evaluation are different at least for delegating constructors and named return value optimization, and thus the rules are in conflict.

Possible resolution:

Change in 11.4.5.1 [class.ctor.general] paragraph 5 as follows:

[ Note: A constructor can be invoked for a const, volatile or const volatile object. const and volatile semantics (9.2.9.2 [dcl.type.cv]) are not applied on an object under construction. They ; they come into effect when the constructor for the most derived object (6.7.2 [intro.object]) ends initialization of the result object completes (6.7.3 [basic.life]). -- end note ]

CWG 2024-02-02

There are various properties that come to be for an object during its initialization. For example, the vtable is fully set up and the destructor will be invoked once the non-delegating constructor completes (issue 2756). The main property of a const object is its immutability from an optimizer perspective. With NRVO (11.9.6 [class.copy.elision]), it is possible to have multiple defining declarations for the same object, for example:

  struct A {
    int x;
  };
  int foo(const A* p)
  {
    A a{10};            // #1
    a.x = 1 + p->x;     // what's the value of a.x?
    return a;
  }
  const A g = foo(&g);  // #2

Given NRVO, both #1 and #2 are declarations of the same object. Those declarations may differ in their cv-qualification for the object. CWG tentatively agreed on the direction that the innermost declaration defines the object's properties, in particular whether it has been initialized and whether it is const.

While NRVO is disallowed in constant evaluation, it was noted that user code can determine whether NRVO occurs at runtime by comparing a pointer to the local object with a pointer to the object in the surrounding context.