Value-initialization of class types

368 views Asked by At

Per cppreference, the syntax for value initialization is:

  • [..]
  • T object {}; (since C++11)
  • [..]

It's already known that value-initialization is performed when an object is constructed with an empty initializer.

Per, [dcl.init]/8 (emphasis mine)

To value-initialize an object of type T means:

  • (8.1) if T is a (possibly cv-qualified) class type ([class]), then
    • (8.1.1) if T has either no default constructor ([class.default.ctor]) or a default constructor that is user-provided or deleted, then the object is default-initialized;
    • (8.1.2) 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;
  • (8.2) [..]
  • (8.3) [..]

I interpret the term "no default constructor" as that there's no default constructor declared in the class. For example,

class S
{
    long double d;
    friend void f(const S&);
};

void f(const S& s) { std::cout << s.d; }

int main()
{
    S s{ };
    f(s); // 0
}

Since the class has "no default constructor", I'm expecting that the object s is default-initialized and the member s.d has indeterminate value. Why that's not the case?

I also have a confusion in understanding the point (8.1.1). How I can write this line of code T object {} without having a default constructor or with having a deleted default constructor? Notice the bold part, It's said that, "if T has either no default constructor or a default constructor that is deleted .."

Are there situations where objects of class types are value-initialized with deleted default constructor or without default constructor at all? Am I misreading 8.1.1?

1

There are 1 answers

7
Miles Budnek On

Your class S does have a default constructor; it is just defined implicitly.

Per [class.default.ctor]/1:

A default constructor for a class X is a constructor of class X for which each parameter that is not a function parameter pack has a default argument (including the case of a constructor with no parameters). If there is no user-declared constructor for class X, a non-explicit constructor having no parameters is implicitly declared as defaulted ([dcl.fct.def]). An implicitly-declared default constructor is an inline public member of its class.

Therefore S{} will zero-initialize the object per [dcl.init]/8.1.2.

When [dcl.init]/8.1.1 refers to classes with no default constructor it means classes where the implicit default constructor doesn't get generated because user-defined constructors exist. That is, (8.1.1) would apply to the following classes:

struct NoDefaultCtor
{
    NoDefaultCtor(int) {}
};

struct UserProvidedDefaultCtor
{
    UserProvidedDefaultCtor() {}
};

struct DeletedDefaultCtor
{
    DeletedDefaultCtor() = delete;
};

For all three of those classes, value-initialization will perform default-initialization. In the case of NoDefaultCtor and DeletedDefaultCtor that default-initialization will fail, of course, but it's important that (8.1.1) catches those types so they don't fall through and get zero-initialized by (8.1.2).