Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clarification and reasons for object lifetime constraints change in C++20

As of C++20, there's a significant change for the constraints of object lifetime from basic.life#8.3 to n4861/basic.life#8.3. The concrete change I want to focus on here is (C++20 draft)

If, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, a new object is created at the storage location which the original object occupied, a pointer that pointed to the original object, a reference that referred to the original object, or the name of the original object will automatically refer to the new object and, once the lifetime of the new object has started, can be used to manipulate the new object, if the original object is transparently replaceable (see below) by the new object. An object o1 is transparently replaceable by an object o2 if

  1. the storage that o2 occupies exactly overlays the storage that o1 occupied, and
  2. o1 and o2 are of the same type (ignoring the top-level cv-qualifiers), and
  3. o1 is not a complete const object, and
  4. neither o1 nor o2 is a potentially-overlapping subobject, and
  5. either o1 and o2 are both complete objects, or o1 and o2 are direct subobjects of objects p1 and p2, respectively, and p1 is transparently replaceable by p2.

vs. the pre-C++20 one (not the only change, see the drafts for details)

  1. the type of the original object is not const-qualified, and, if a class type, does not contain any non-static data member whose type is const-qualified or a reference type...

Question 1: Maybe too obvious, just to be sure: With complete const object, the standard refers to complete objects that are const, right? (So it has nothing to do with partial/full const objects that was part of the previous quality of wording within this section?)

Question 2: Can anyone explain the reasons behind these changes (aliasing?)?

Question 3: Is my assumption valid, that this one is a heavy relaxation of the former rules, i.e. guaranteeing now a lot more object/memory reusage scenarios not to be UB for instance? In doubt, shouldn't they affect the way the optimizers are allowed to operate in a heavy way too (shift of efficiency fields)?

like image 525
Secundi Avatar asked Jan 31 '26 01:01

Secundi


1 Answers

Q1: Yes. Also, it's unrelated whether a member is const when determining which object is a "complete const object". E.g.

struct HasConstMem { const int n = 42; };
HasConstMem       foo;  // not a complete const object
const HasConstMem bar;  // a complete const object

auto px = new HasConstMem;       // points to a complete non-const object
auto py = new const HasConstMem; // points to a complete const object

Q2: IMO, the old specification didn't allow std::vector<HasConstMem> work without std::launder, which is defective.

Q3: There're theoretically some techniques disallowed for optimizers, but these techniques shouldn't have been existing, otherwise the behavior of std::vector is already shown broken before. In C++20, std::vector is made constexpr (P1004R2), and the defect became obvious since core language UB is required to be diagnosed in constant evaluation to cause a failure (N4868 [expr.const]/5.7).

like image 141
F.v.S. Avatar answered Feb 01 '26 18:02

F.v.S.



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!