6
votes

According to cppreference non-union class types without any user-provided constructors will be zero-initialized before being constructed:

If T is an non-union class type without any user-provided constructors, then the object is zero-initialized and then the implicitly-declared default constructor is called (unless it's trivial)

I'm not sure what should happen when the c++11 inherited constructors are used since the quote explicitly mentions the implicitly-declared default constructor.

Given the following example:

#include <iostream>

struct A {
    int a;
    A() {}
    A(int i): a(i) {}
};

struct B: public A {
    using A::A;
};

int main() {
    B b { 5 };
    B* p = new (&b) B{ };
    std::cout << b.a << std::endl;
}

What is the correct output, 0 or 5? Should a class type exclusively providing inherited constructors be zero-initialized before value-initialization (B{ })?

1

1 Answers

6
votes

The correct answer is 0 because the default constructor for B is implicitly declared.

Note that default, copy & move constructors are not inherited; quoting from §12.9/3 [class.inhctor]

For each non-template constructor in the candidate set of inherited constructors other than a constructor having no parameters or a copy/move constructor having a single parameter, a constructor is implicitly declared with the same constructor characteristics unless there is a user-declared constructor with the same signature in the complete class where the using-declaration appears or the constructor would be a default, copy, or move constructor for that class.


Your example is similar to the one listed in N3797, §12.9/6 (edited for brevity)

struct B2 {
  B2(int = 13, int = 42);
};

struct D2 : B2 {
  using B2::B2;
};

The candidate set of inherited constructors in D2 for B2 is
B2(const B2&)
B2(B2&&)
B2(int = 13, int = 42)
B2(int = 13)
B2()

The set of constructors present in D2 is
D2(), implicitly-declared default constructor, not inherited
D2(const D2&), implicitly-declared copy constructor, not inherited
D2(D2&&), implicitly-declared move constructor, not inherited
D2(int, int), implicitly-declared inheriting constructor
D2(int), implicitly-declared inheriting constructor

In your case, the candidate set of inherited constructors in B for A are

A()
A(int)
A(const& A)
A(A&&)

and the constructors present in B are

B() implicitly declared, not inherited
B(int) implicitly declared, inherited
B(const& B) implicitly declared, not inherited
B(B&&) implicitly declared, not inherited