cplusplus / CWG

Core Working Group
24 stars 7 forks source link

[basic.life] p1.5 and [intro.object] p3 have a circular dependency on each other #247

Open xmh0511 opened 1 year ago

xmh0511 commented 1 year ago

Full name of submitter (unless configured in github; will be published with the issue): Jim X

[basic.life] p1.5 says:

The lifetime of an object o of type T ends when:

  • [...]
  • the storage which the object occupies is released, or is reused by an object that is not nested within o ([intro.object]).

The wording implies: if an object o2 reuses the storage occupied by o1 but o2 is nested within o1, o2 does not end the lifetime of o1.

[intro.object] p3 says

If a complete object is created ([expr.new]) in storage associated with another object e of type “array of N unsigned char” or of type “array of N std​::​byte” ([cstddef.syn]), that array provides storage for the created object if:

  • the lifetime of e has begun and not ended, and

The first requirement says the lifetime of e is not ended. In other words, whether o2 is nested within o1 or not is first determined by whether o2 reuses the storage of o1 will end the lifetime of o1, and the latter is, in turn, determined by whether o2 is nested within o1 per [basic.life] p1.5.

Suggested resolution

that array provides storage for the created object if:

  • the lifetime of e has begun and not ended other than the created object reused the storage would end the lifetime of e

The added wording intends to mean: we uniformly assume that the reuse of the storage can end the lifetime, and we say the lifetime e shouldn't be ended other than the former case, which can break the circular dependency. If other requirements all be satisfied, then we say e provides storage for the created object, hence the created object does not actually end the lifetime of the object providing the storage.

frederick-vs-ja commented 2 months ago

Is there any case where contradictory or ambiguous result for whether storage providing happens would be inferred?

The crux seems to be: whether the new object is nested within the array depends on whether the array is within its lifetime. But given lifetime ending of the previously living array should only happens when [intro.object] p3.2 isn't met (i.e. the new object isn't exactly fit within the array), is there really a problematic case?

xmh0511 commented 2 months ago

Is there any case where contradictory or ambiguous result for whether storage providing happens would be inferred?

The crux seems to be: whether the new object is nested within the array depends on whether the array is within its lifetime. But given lifetime ending of the previously living array should only happens when [intro.object] p3.2 isn't met (i.e. the new object isn't exactly fit within the array), is there really a problematic case?

It has been a long time since this issue was posted, I a bit forget what this issue focused on. Consider this example:

int main(){
   unsigned char arr[2]; // o1
   using Type = unsigned char [2];
   new (arr) Type; // o2
}

Is the lifetime of o1 ended by o2? Looking into [basic.life] p1.5

The lifetime of an object o of type T ends when:

  • [...]
  • the storage which the object occupies is released, or is reused by an object that is not nested within o ([intro.object]).

Does o2 reuse the storage occupied by o1? Yes. So, is the o2 not nested within o1? Looking into [intro.object] p4

An object a is nested within another object b if

  • [...]
  • b provides storage for a, or

Does o1 provide storage for o2? Looking into [intro.object] p3

If a complete object is created ([expr.new]) in storage associated with another object e of type “array of N unsigned char” or of type “array of N std​::​byte” ([cstddef.syn]), that array provides storage for the created object if

  • the lifetime of e has begun and not ended, and

So, is the lifetime of o1 ended? Go back to the first step and we infinitely loop.

frederick-vs-ja commented 2 months ago

So, is the lifetime of o1 ended? Go back to the first step and we infinitely loop.

I think the only reading that can make sense is that whether "the lifetime of e has begun and not ended" is logically determined immediately before the reusing. Is this something that can't be concluded from the current wording?