fspeech
fspeech

Reputation: 75

C++ memberwise initialization and constructors

Without defining a constructor I am able to use memberwise initialization:

struct B {
  A a_;
};

and later on it okay to say

B b {A()};

This is efficient as no copy or move of A is involved. However as soon as I define a move constructor for B the above code no longer compiles. How can I have both memberwise initialization and some constructors coexist?

Upvotes: 2

Views: 1444

Answers (2)

Jay Miller
Jay Miller

Reputation: 2234

The answer given by R Sahu is already correct, but I'd like to add that there is no loss of efficiency to add a constructor that does what your memberwise-initialization does:

struct B {
  A a_;
  B(const A& a) : a_(a) {}
}

Now calling B b {A()}; is exactly as efficient as it was when you were using aggregate-initialization.

UPDATE: After reading the comments I've tested my assertion:

struct Foo
{
        Foo() { std::cout << "Foo default" << std::endl; }
        Foo(const Foo& other) { std::cout << "Foo copy" << std::endl; }
};

struct Bar
{
        Foo f;
        // #1 Bar(const Foo& f) : f(f) {}
};

int main()
{
        Bar b { Foo() };
}

As shown above this application outputs just

Foo default

If I uncomment #1 I then get

Foo default
Foo copy

as the original poster suggested (GCC 4.9 with -O3). I have to play more with non-printing constructors to see if this is always true or just when there are side effects, but I wanted to update this post to clarify that it is not as cut and dry as I suggested.

Upvotes: 1

R Sahu
R Sahu

Reputation: 206717

The way it is defined, B is an aggregate type if A is an aggregate type.

B b {A()};

is aggregate initialization.

When you add a move constructor to B, B stops being an aggregate type. Hence, you can't use aggregate initialization to initialize an instance of B.

From the standard (emphasis mine):

8.5.1 Aggregates [dcl.init.aggr]

1 An aggregate is an array or a class (Clause 9) with no user-provided constructors (12.1), no brace-or-equalinitializers for non-static data members (9.2), no private or protected non-static data members (Clause 11), no base classes (Clause 10), and no virtual functions (10.3)

Upvotes: 3

Related Questions