cplusplus / CWG

Core Working Group
23 stars 7 forks source link

[intro.object] Inconsistent specification on whether a subobject is considered created #386

Open frederick-vs-ja opened 1 year ago

frederick-vs-ja commented 1 year ago

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

Reference (section label): [intro.object]

Link to reflector thread (if any):

Issue description:

[intro.object] p1 states:

An object is created by a definition, by a new-expression ([expr.new]), by an operation that implicitly creates objects (see below), when implicitly changing the active member of a union, or when a temporary object is created ([conv.rval], [class.temporary]).

It is inconsistent whether subobjects is considered created among these operations.

  1. In a definition of an object, only the complete object is considered defined, which possibly implies that only the complete object is considered created.
  2. In a new-expression, as noticed by @languagelawyer in https://github.com/cplusplus/CWG/issues/378#issuecomment-1657924778, the wording in [expr.new] strongly indicates that only one (the outermost) object is created by a new-expression itself.
  3. For operations that implicitly object create objects, notes and examples in [intro.object] indicate that subobjects can be implicitly created.
  4. In [class.union.general], subobjects are not excluded from the set of implicitly created objects, and it is intended that some subobjects are implicitly created as needed.
  5. For temporary objects, [class.temporary] seemingly implies that only the complete temporary object is considered created.

Moreover, a note in [class.abstract] implies that a base class subobject of an abstract class type may be created. Note that such a base class subobject can't be implicitly created.

It seems better to handle subobjects consistently. Personally, I think it is easier to specify that a subobject is generally considered created together with its complete object (except for the case of an inactive union member). And it may be possible to unify cases for definitions, new-expressions, and temporary objects with "initialization".

Suggested resolution:

languagelawyer commented 1 year ago

For operations that implicitly object create objects, notes and examples in [intro.object] indicate that subobjects can be implicitly created.

In the example you linked, X can be implicitly created (and has its subobjects, but they are not «created»), and then 2 int objects can be implicitly-created, ontop of subobjects, and become «created» subobjects per https://timsong-cpp.github.io/cppwp/n4868/intro.object#2.sentence-4.

I think the same reasoning may apply to the union example.

So, these are not proofs that subobjects are considered «created», other than by https://timsong-cpp.github.io/cppwp/n4868/intro.object#2.sentence-4

frederick-vs-ja commented 1 year ago

In the example you linked, X can be implicitly created (and has its subobjects, but they are not «created»), and then 2 int objects can be implicitly-created, ontop of subobjects, and become «created» subobjects per https://timsong-cpp.github.io/cppwp/n4868/intro.object#2.sentence-4.

Thanks. Your interpretation was likely to make sense, although I still think such mechanism is a bit too tricky.

After checking [intro.object] p2.1, I think if we just make the initialization of a subobject (within the initialization of the complete object) create that object, there might be conflict since the lifetime of the complete object hasn't begun.

(But I still wonder whether there can be a less tricky and more consistent specification...)

There's possibly a loophole: these objects are implicitly created at the same time (same for objects in the case for union), so it's doubtful whether we can say "the containing object's lifetime has begun" or "and then".

xmh0511 commented 11 months ago

I even suspect whether an object(including subobject) whose lifetime has ended or hasn't begun can be called an "object". [basic.life] p4 says:

The properties ascribed to objects and references throughout this document apply for a given object or reference only during its lifetime.

So, the stuff should be alive or was alive if we called it an object. Otherwise, it is just a storage region. So, the array element and the subobject should be separated, the array element is a slot that provides storage regions for subobjects.

Also, we should have some terms that name the slots that provide storage for member subobjects instead of saying these storage regions are member subobjects.


There's possibly a loophole: these objects are implicitly created at the same time (same for objects in the case for union), so it's doubtful whether we can say "the containing object's lifetime has begun" or "and then".

[basic.life] p1 says

The lifetime of an object of type T begins when:

  • [...]
  • its initialization (if any) is complete (including vacuous initialization) ([dcl.init]),

The initialization of a complete object of class type comprises the initializations for all subobjects. So, the lifetime of the complete object begins only if all initialization thereof has been completed. Moreover, basic.life#6 implies this point

Before the lifetime of an object has started but after the storage which the object will occupy has been allocated ... For an object under construction or destruction, see [class.cdtor].

So, I don't think the subobjects will be treated as separately created when the complete object is created, note the precondition of intro.object#2

the lifetime of e's containing object has begun and not ended, and

So, either the reading is wrong or there is a large bug about the object model in the current document.