Repository navigation
CWG2820 [dcl.init.general] Zero-initialization VS default constructors #40
Description
Activity
See CWG1324 and CWG1368 (resolved by CWG1301).
The latest edit to that paragraph was via CWG1507.@frederick-vs-ja , please do me a favor and double-check that the proposed edits don't revert or otherwise negatively affect those existing (and resolved) core issues, i.e. that we're not introducing a regression.
I'm not sure whether the second initialization(i.e. default-initialization creates an object
o2) will end the lifetime of the objecto1that is begun by the first initialization(i.e. zero-initialization), which is regarded as a reuse of the storage occupied byo1. Anyway, [class.ctor.general] p3 saysAn object created in this way is unnamed.
[dcl.init.general] p20
An object whose initialization has completed is deemed to be constructed, even if the object is of non-class type or no constructor of the object's class is invoked for the initialization.
We do not like the double-initialization and the subsequent confusion caused by such initialization
maybe CWG wishes to somehow remove the double-initialization to make this clear
See cplusplus/draft#4802 and the linked questions in that issue.
@jensmaurer I'm sure that the suggested resolutions only change the conditions under which zero-initialization is performed. So existing resolutions won't be broken. Anyway, the semantic constraints for default-initialization are always needed to be checked.
@xmh0511 I think the wording can "magically" ensure that there is only
o1and noo2, so reuse doesn't happen.[class.ctor.general] p3 is talking about functional notation type conversion, although it was accidently made dangling by P1787.
Perhaps we should resolve double-initialization uniformly elsewhere, and discussion for delegating constructors may be needed.
I think the wording can "magically" ensure that there is only o1 and no o2, so reuse doesn't happen.
AFAIK, each initialization will construct an object. An object cannot be initialized twice. If it were, it wouldn't make sense or conform to intuitive. Again, if the initializations of the object in this issue are the zero-initialization followed by the default-initialization, which of them starts the lifetime of the object?
AFAIK, each initialization will construct an object. An object cannot be initialized twice.
Perhaps we shouldn't apply this model to objects of trivially default constructible (and/or implicit-lifetime?) types, in order to start their lifetime as quickly as possible. Implementations can (and probably do) support zero-initialization followed by dynamic initialization, and there're probably a lot of programs depending on this.
Again, if the initializations of the object in this issue are the zero-initialization followed by the default-initialization, which of them starts the lifetime of the object?
IMO for objects (including subobjects) of trivially default constructible types, their lifetime should be started by zero-initialization; for other objects, zero-initialization is not sufficient to start their lifetime.
Anyway, I think regularization or removal of double-initailziation should be handled as another issue.
CWG2820 partially addresses this (a weak form of Option B is proposed).
- changed the title
[-][dcl.init.general] Zero-initialization VS default constructors[/-][+]CWG2820 [dcl.init.general] Zero-initialization VS default constructors[/+]on Nov 1, 2023 I think the wording can "magically" ensure that there is only o1 and no o2, so reuse doesn't happen.
AFAIK, each initialization will construct an object. An object cannot be initialized twice. If it were, it wouldn't make sense or conform to intuitive. Again, if the initializations of the object in this issue are the zero-initialization followed by the default-initialization, which of them starts the lifetime of the object?
How sure are you of that?
I only encountered the issue of default-after-zero initialization this weekend and haven't spent more than, at most, ten hours looking, but I cannot find any statement that an object cannot be initialized after it has been initialized.
RE https://cplusplus.github.io/CWG/issues/2820.html
The suggested change is
otherwise, the object is zero-initialized and
the semantic constraints for default-initialization are checked, and if T has a non-trivial default constructor, the object isthen default-initializedWhich leaves my pet scenario with a double-initialization:
struct T { Nontrivial nt{20}; }; int main() { T t{}; }
The order, if I got the Standard right, is:
tis list-initialized- List initialization of a class using an empty list is value-initialization
T's implicitly defaulted ctor is non-trivial because ofnt{20};- So
tis zero-initialized, then default-initialized.
And so, again,
t.ntis initialized twice - first zero-initialized during the zero-initialization oft, then initialized again with the brace-or-equal-initializer during the default construction oft.EDIT
I can tell you what resolution I would prefer here:
Value initializing an object of class type will recursively value-initialize every base class and sub-object, picking their initializers in this prioritized order:
- as specified in the member-initializer-list if available,
- else the default-member-initializer if available,
- else the objects default ctor if available,
- else, if the subobject is of scalar type, integer literal zero,
- else, the program is ill formed (diagnostic required)
Clear. Obvious. Probably politically impossible.
My secondary preference would be some intricate wording to indicate that value initialization does zero-initialization as before but only for sub-objects that are not mentioned member initializer lists and which do not have Default Member Initializers.
My tertiary preference is to redefine "zero-initialization" of subobjects to set values to integer literal zero unless the sub-object is present in a member-initializer-list or a default member initializer is present, in which case zero initialization picks that value instead of zero.
(Two and three have the same actual effect, it's just whether you say "don't zero-initialize sub-objects with other initializers" or "do zero-initialize sub-objecst with other initializers, but we'll redefine what zero-initialize means."
Full name of submitter (unless configured in github; will be published with the issue): Jiang An
Reference (section label): [dcl.init.general]
Link to reflector thread (if any):
Issue description:
A class may be default-initializable while having more than one default constructors. In such cases, implementations don't consider any unselected default constructors during value-initialization, and may perform zero-initialization.
This strategy is slightly different from [dcl.init.general]/9 which doesn't exclude unselected defaulted constructors. Perhaps zero-initialization is desired and [dcl.init.general]/9 should be modified to match implementations.
[dcl.init.general]/(9.1.2) seemly indicates that if the default constructor is defaulted (not user-provided) and non-trivial, then the object is zero-initialized and then default-initialized. The current wording might have some drawbacks and lead to implement divergence:
Example:
Suggested resolution:
There are two mutually exclusive suggested resolutions. Option A exclusively selects zero-initialization or default-initialization (matching gcc etc.), while Option B sometimes perform both forms (matching msvc, seemly the status quo).
Option A:
Change [dcl.init.general]/(9.1) as indicated:
Option B:
Change [dcl.init.general]/(9.1) as indicated: