Initializing a member array in constructor initializer

class C
{
public: C() : arr({1,2,3}) //doesn't compile
{} /* C() : arr{1,2,3} //doesn't compile either
{} */
private: int arr[3];
};

I believe the reason is that arrays can be initialized only with = syntax, that is:

int arr[3] = {1,3,4};

Questions

  1. How can I do what I want to do (that is, initialize an array in a constructor (not assigning elements in the body)). Is it even possible?
  2. Does the C++03 standard say anything special about initializing aggregates (including arrays) in ctor initializers? Or the invalidness of the above code is a corollary of some other rules?
  3. Do C++0x initializer lists solve the problem?

P.S. Please do not mention vectors, boost::arrays, and their superiority to arrays, which I am well aware of.

2

8 Answers

  1. How can I do what I want to do (that is, initialize an array in a constructor (not assigning elements in the body)). Is it even possible?

Yes. It's using a struct that contains an array. You say you already know about that, but then I don't understand the question. That way, you do initialize an array in the constructor, without assignments in the body. This is what boost::array does.

Does the C++03 standard say anything special about initializing aggregates (including arrays) in ctor initializers? Or the invalidness of the above code is a corollary of some other rules?

A mem-initializer uses direct initialization. And the rules of clause 8 forbid this kind of thing. I'm not exactly sure about the following case, but some compilers do allow it.

struct A { char foo[6]; A():foo("hello") { } /* valid? */
};

See this GCC PR for further details.

Do C++0x initializer lists solve the problem?

Yes, they do. However your syntax is invalid, I think. You have to use braces directly to fire off list initialization

struct A { int foo[3]; A():foo{1, 2, 3} { } A():foo({1, 2, 3}) { } /* invalid */
};
1

C++98 doesn't provide a direct syntax for anything but zeroing (or for non-POD elements, value-initializing) the array. For that you just write C(): arr() {}.

I thing Roger Pate is wrong about the alleged limitations of C++0x aggregate initialization, but I'm too lazy to look it up or check it out, and it doesn't matter, does it? EDIT: Roger was talking about "C++03", I misread it as "C++0x". Sorry, Roger. ☺

A C++98 workaround for your current code is to wrap the array in a struct and initialize it from a static constant of that type. The data has to reside somewhere anyway. Off the cuff it can look like this:

class C
{
public: C() : arr( arrData ) {}
private: struct Arr{ int elem[3]; }; Arr arr; static Arr const arrData;
};
C::Arr const C::arrData = {{1, 2, 3}};
3

Workaround:

template<class T, size_t N>
struct simple_array { // like std::array in C++0x T arr[N];
};
class C : private simple_array<int, 3>
{ static simple_array<int, 3> myarr() { simple_array<int, 3> arr = {1,2,3}; return arr; }
public: C() : simple_array<int, 3>(myarr()) {}
};
  1. No, unfortunately.
  2. You just can't in the way you want, as it's not allowed by the grammar (more below). You can only use ctor-like initialization, and, as you know, that's not available for initializing each item in arrays.
  3. I believe so, as they generalize initialization across the board in many useful ways. But I'm not sure on the details.

In C++03, aggregate initialization only applies with syntax similar as below, which must be a separate statement and doesn't fit in a ctor initializer.

T var = {...};

How about

... C() : arr{ {1,2,3} }
{}
...

?

Compiles fine on g++ 4.8

2

I found this question very useful, but found no example for the case when the member array element is an object without default constructor and with deleted copy/move constructors. In other words the example that initializes the member array without unnecessary object copy.

For example, with a following class A:

class A { public: int v; A(int v) : v(v) { } A() = delete; A(A &&) = delete; A(const A &) = delete; A &operator =(A &&) = delete; A &operator =(const A &) = delete;
};

In-place initialization with non-default constructor would look like:

class B { public: A a[3]; B() : a { {1}, {2}, {3} } {}
};

This worked for me using C++17 on Windows:

File A.h:

class A
{ private: float arrayVar[3];
}

File A.cpp:

A::A() : arrayVar{ 0.0f, 0.0f, 0.0f } { }

You want to init an array of ints in your constructor? Point it to a static array.

class C
{
public: int *cArray;
};
C::C { static int c_init[]{1,2,3}; cArray = c_init;
}
1

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

You Might Also Like