Skip to content

CWG2820 [dcl.init.general] Zero-initialization VS default constructors #40

Closed
cplusplus/draft
#6906
@frederick-vs-ja

Description

@frederick-vs-ja

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:

  1. 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.

  2. [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:

    • Some implementations (gcc, icc, and clang) only perform default-initialization in this case, while others (msvc) perform both operations.
    • When the default constructor is trivial, it is unobservable whether it is called after zero-initialization, so perhaps the default-initialization can be performed unconditionally.

Example:

struct Foo {
    int x;
    Foo() = default;
    template<class T>
    Foo(T = T()) {} // user-provided, also a default constructor
};

template<int N>
struct Bar {
    int y;
    Bar() requires (N >= 0) = default;
    Bar() requires (N < 0) {} // user-provided
};

static_assert(Foo().x == 0); // passes
static_assert(Bar<0>().y == 0); // passes if supported

struct Baz {
    int z;
    int w = 1;
    Baz() = default; // non-trivial
};

static_assert(Baz().z == 0); // passes on msvc, fails on gcc, icc, and clang

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:

if T is a (possibly cv-qualified) class type ([class]), the semantic constraints for default-initialization are checked, and then

  • if T has either no default constructor ([class.default.ctor]) or a default constructor that is user-provided or deleted there is no selected default constructor ([class.default.ctor]) for default-initialization, or the selected default constructor is non-trivial or deleted, then the object is default-initialized;
  • 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 is default-initialized;

Option B:

Change [dcl.init.general]/(9.1) as indicated:

if T is a (possibly cv-qualified) class type ([class]), the semantic constraints for default-initialization are checked, and then

  • if T has either no default constructor ([class.default.ctor]) or a default constructor that is user-provided or deleted there is no selected default constructor ([class.default.ctor]) for default-initialization, or the selected default constructor is user-provided or deleted, then the object is default-initialized;
  • 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 is then default-initialized;

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions