6

g++ 4.7 supports array member initialization and I started playing with it.

The code below does not compile.

struct A
{
   A(int){};
   A(const A&) = delete;
   A& operator=(const A&) = delete;
   ~A(){};
};

struct B
{
   B():
      a{{0},{1}}
   {};
   A a[2];
};

B b;

The error message with gcc 4.8 (prerelease) is:

n.cc: In constructor ‘B::B()’:
n.cc:12:20: error: use of deleted function ‘A::A(const A&)’
           a{{0},{1}}
             ^
n.cc:4:8: error: declared here
        A(const A&) = delete;
        ^

Is there a way to make this code work? I can't easily change the contructors,destructor of A. I seem to need a move-constructor or copy-constructor to initialize the array, but this seems counter-intuitive, since all I really want is in-place construction.

It works if I split a[2] in 2 members a0 and a1, and construct them separately. This looks fishy however.

1
  • ':' in a constructor uses copy constructors to assign values, and you delete it in A thus giving you an error. Commented Dec 14, 2012 at 21:06

2 Answers 2

4

Within list-initialization (8.5.4p1) of an aggregate (8.5.1), the form of initialization performed on the elements of the aggregate is copy-initialization (8.5.1p2), even if the initialization is direct-list-initialization:

When an aggregate is initialized by an initializer list, as specified in 8.5.4, the elements of the initializer list are taken as initializers for the members of the aggregate, in increasing subscript or member order. Each member is copy-initialized from the corresponding initializer-clause.

However, just because the form of initialization performed is copy-initialization doesn't mean that a copy occurs. As per copy-list-initialization of non-copyable types, copy-list-initialization should be identical to direct-list-initialization with the exception that explicit constructors are not allowed.

Sign up to request clarification or add additional context in comments.

Comments

2

Arrays are aggregates, and aggregate initialization always uses copy initialization. C++11 §8.5.1/1:

An aggregate is an array or a class with no user-provided constructors, no brace-or-equal-initializers for non-static data members, no private or protected non-static data members, no base classes, and no virtual functions.

§8.5.1/2:

When an aggregate is initialized by an initializer list, as specified in 8.5.4, the elements of the initializer list are taken as initializers for the members of the aggregate, in increasing subscript or member order. Each member is copy-initialized from the corresponding initializer-clause.

(Emphasis mine.)

Additionally, the compiler does not implicitly generate a move constructor if a user-declared copy constructor is present (§12.8/9); because you have a user-declared copy constructor that is defined as deleted, A has neither a copy nor a move constructor. Explicitly adding a move constructor works:

struct A
{
   A(int) { }
   A(A const&) = delete;
   A& operator = (A const&) = delete;
   A(A&&) = default;
   ~A() = default;
};

struct B
{
   B() : a{{0}, {1}} { }
   A a[2];
};

int main()
{
   B b;
}

Online demo

This is about as close to what you want as you're going to get.

1 Comment

Not the answer I was hoping for, but thanks for the detailed explanation.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.