C ++: constructor initializer for arrays

I'm having a brain cramp ... how can I properly initialize an array of objects in C ++?

example without an array:

struct Foo { Foo(int x) { /* ... */ } }; struct Bar { Foo foo; Bar() : foo(4) {} }; 
Array Example

:

 struct Foo { Foo(int x) { /* ... */ } }; struct Baz { Foo foo[3]; // ??? I know the following syntax is wrong, but what correct? Baz() : foo[0](4), foo[1](5), foo[2](6) {} }; 

edit: Wild and crazy workarounds are appreciated, but they won't help me in my case. I am working on an embedded processor where std :: vector and other STL constructors are not available, and the obvious workaround is to create a default constructor and have an explicit init() method that can be called after the build time, so I donโ€™t need to use initializers at all. (This is one of those cases where I messed up the Java final keyword + flexibility with constructors.)

+59
c ++ constructor initializer
Mar 09
source share
14 answers

There is no way. You need a default constructor for the members of the array, and it will be called, after which you can perform any initialization that you want in the constructor.

+48
Mar 09 '10 at 14:48
source share

To update this question for C ++ 11, now it can be done very naturally:

 struct Foo { Foo(int x) { /* ... */ } }; struct Baz { Foo foo[3]; Baz() : foo{{4}, {5}, {6}} { } }; 

These braces can also be reduced even more concisely:

 struct Baz { Foo foo[3]; Baz() : foo{4, 5, 6} { } }; 

Which can be easily extended to multidimensional arrays:

 struct Baz { Foo foo[3][2]; Baz() : foo{1, 2, 3, 4, 5, 6} { } }; 
+25
Jun 26
source share

You cannot currently use the initialization list for array elements. You are stuck doing it hard.

 class Baz { Foo foo[3]; Baz() { foo[0] = Foo(4); foo[1] = Foo(5); foo[2] = Foo(6); } }; 

In C ++ 0x you can write:

 class Baz { Foo foo[3]; Baz() : foo({4, 5, 6}) {} }; 
+16
Mar 09 '10 at 14:51
source share

Unfortunately, there is no way to initialize array elements to C ++ 0x.

You can use std :: vector and push_back instances of Foo in the constructor body.

You can give Foo a default constructor (maybe private and make Baz a friend).

You can use an array object that is copyable (boost or std :: tr1) and is initialized from a static array:

 #include <boost/array.hpp> struct Baz { boost::array<Foo, 3> foo; static boost::array<Foo, 3> initFoo; Baz() : foo(initFoo) { } }; boost::array<Foo, 3> Baz::initFoo = { 4, 5, 6 }; 
+7
Mar 09 '10 at 15:46
source share

You can use the C ++ 0x auto keyword along with the template specialization , for example, with the name boost::make_array() (similar to make_pair() ). For the case when N is 1 or 2 arguments, we can then write option A as

 namespace boost { /*! Construct Array from @p a. */ template <typename T> boost::array<T,1> make_array(const T & a) { return boost::array<T,2> ({{ a }}); } /*! Construct Array from @pa, @p b. */ template <typename T> boost::array<T,2> make_array(const T & a, const T & b) { return boost::array<T,2> ({{ a, b }}); } } 

and option B as

 namespace boost { /*! Construct Array from @p a. */ template <typename T> boost::array<T,1> make_array(const T & a) { boost::array<T,1> x; x[0] = a; return x; } /*! Construct Array from @pa, @p b. */ template <typename T> boost::array<T,2> make_array(const T & a, const T & b) { boost::array<T,2> x; x[0] = a; x[1] = b; return x; } } 

GCC-4.6 with -std=gnu++0x and -O3 generates the same binary for

 auto x = boost::make_array(1,2); 

using both A and B as for

 boost::array<int, 2> x = {{1,2}}; 

For user-defined types (UDTs), however, option B leads to an additional copy constructor , which usually slows down and should therefore be avoided.

Note that boost::make_array when called with explicit char array literals, as in the following case

 auto x = boost::make_array("a","b"); 

I believe this is good, since const char* literals can be deceiving when using them.

Variadic templates , available in GCC since version 4.5, can be used to reduce the template specialization code label code for each N in the definition of one template boost::make_array() is defined as

 /*! Construct Array from @pa, @p b. */ template <typename T, typename ... R> boost::array<T,1+sizeof...(R)> make_array(T a, const R & ... b) { return boost::array<T,1+sizeof...(R)>({{ a, b... }}); } 

This works pretty much as we expect. The first argument defines the boost::array template T argument, and all other arguments are converted to T In some cases, this may be undesirable, but I'm not sure how this can be indicated using variation patterns.

Perhaps boost::make_array() should go into Boost libraries?

+3
Jun 15 2018-11-11T00:
source share

This seems to work, but I'm not sure if this is correct:

 #include <iostream> struct Foo { int x; Foo(int x): x(x) { } }; struct Baz { Foo foo[3]; static int bar[3]; // Hmm... Baz() : foo(bar) {} }; int Baz::bar[3] = {4, 5, 6}; int main() { Baz z; std::cout << z.foo[1].x << "\n"; } 

Output:

 $ make arrayinit -B CXXFLAGS=-pedantic && ./arrayinit g++ -pedantic arrayinit.cpp -o arrayinit 5 

Caution emptor.

Edit: No, Como rejects him.

Another edit: this is kind of a hoax, it just pushes member initialization of the array in a different place. Therefore, Foo requires a default constructor, but if you do not have std::vector , you can implement the absolute minimum you need:

 #include <iostream> struct Foo { int x; Foo(int x): x(x) { }; Foo(){} }; // very stripped-down replacement for vector struct Three { Foo data[3]; Three(int d0, int d1, int d2) { data[0] = d0; data[1] = d1; data[2] = d2; } Foo &operator[](int idx) { return data[idx]; } const Foo &operator[](int idx) const { return data[idx]; } }; struct Baz { Three foo; static Three bar; // construct foo using the copy ctor of Three with bar as parameter. Baz() : foo(bar) {} // or get rid of "bar" entirely and do this Baz(bool) : foo(4,5,6) {} }; Three Baz::bar(4,5,6); int main() { Baz z; std::cout << z.foo[1].x << "\n"; } 

z.foo is not really an array, but it looks about the same as a vector. Adding the begin() and end() functions to Three is trivial.

+2
Mar 09 '10 at 14:56
source share

When creating objects in an array, you can only call the default constructor.

+1
Mar 09 '10 at 14:51
source share

In the specific case, when the array is a member of the class data, you cannot initialize it in the current version of the language. There is no syntax for this. Either specify the default constructor for the elements of the array, or use std::vector .

A single array can be initialized using an aggregate initializer.

 Foo foo[3] = { 4, 5, 6 }; 

but, unfortunately, there is no corresponding syntax for the list of constructor initializers.

+1
Mar 09 '10 at 14:51
source share

There is no syntax for constructing an array that can be used in this context, at least not directly. You can accomplish what you are trying to accomplish with the following:

 Bar::Bar() { static const int inits [] = {4,5,6}; static const size_t numInits = sizeof(inits)/sizeof(inits[0]); std::copy(&inits[0],&inits[numInits],foo); // be careful that there are enough slots in foo } 

... but you need to tell Foo the default constructor.

0
Mar 09 '10 at 14:56
source share

Ideas from a twisted mind:

 class mytwistedclass{ static std::vector<int> initVector; mytwistedclass() { //initialise with initVector[0] and then delete it :-) } }; 

now set this initVector to what you need before you instantiate the object. Then your objects are initialized with your parameters.

0
Mar 09 '10 at 15:05
source share

You can do it, but it is not beautiful:

 #include <iostream> class A { int mvalue; public: A(int value) : mvalue(value) {} int value() { return mvalue; } }; class B { // TODO: hack that respects alignment of A.. maybe C++14 alignof? char _hack[sizeof(A[3])]; A* marr; public: B() : marr(reinterpret_cast<A*>(_hack)) { new (&marr[0]) A(5); new (&marr[1]) A(6); new (&marr[2]) A(7); } A* arr() { return marr; } }; int main(int argc, char** argv) { B b; A* arr = b.arr(); std::cout << arr[0].value() << " " << arr[1].value() << " " << arr[2].value() << "\n"; return 0; } 

If you put this in your code, I hope you have a VERY good reason.

0
Feb 29 '16 at 17:23
source share

This is my solution for your reference:

 struct Foo { Foo(){}//used to make compiler happy! Foo(int x){/*...*/} }; struct Bar { Foo foo[3]; Bar() { //initialize foo array here: for(int i=0;i<3;++i) { foo[i]=Foo(4+i); } } }; 
0
May 05 '17 at 6:47 a.m.
source share

in visual studio 2012 or higher, you can do it like

 struct Foo { Foo(int x) { /* ... */ } }; struct Baz { Foo foo[3]; Baz() : foo() { } }; 
-one
Jan 13 '16 at 7:56
source share
 class C { static const int myARRAY[10]; // only declaration !!! public: C(){} } const int C::myARRAY[10]={0,1,2,3,4,5,6,7,8,9}; // here is definition int main(void) { C myObj; } 
-3
Jun 10 '13 at 18:43
source share



All Articles