Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initialize array in constructor without using default constructor or assignment

Consider:

struct A {

 A (int);

 A (const A &);
};

struct B {

 A foo [2];

 B (const A & x, const A & y)
 : foo {x, y} /* HERE IS THE PROBLEM */
 {}
};

I was expecting this to work since I'm using C++0x support in GCC4.3, which allegedly supports initialiser lists. No joy.

I have a class A which has no default constructor. This is not negotiable. Assignment post-default is not an option.

I am trying to create B which uses A. B::foo may not be std::vector.

How can I initialise B::foo in B(...), constructing its elements exactly once?

At the moment, I am condidering replacing B with

struct B {

A foo_a;

B foo_b;

A * foo () {
assert ((&foo_b) - *&foo_a) == 1);
return &foo_a;
}

B (const A & x, const A & y) : foo_a(x), foo_b(y) {}
};

Or even using char foo [2*sizeof(A)] with placement new -- YUK!

Surely there's a proper way to do this?

like image 257
spraff Avatar asked Sep 26 '10 14:09

spraff


3 Answers

You can use boost::array. It has a plain native array inside, so it still has the same memory layout like in your example.

struct B {
 boost::array<A, 2> foo;

 B (const A & x, const A & y)
 : foo(createFoo(x, y))
 {}

private:
 static boost::array<A, 2> createFoo(const A & x, const A & y) {
   boost::array<A, 2> a = {{ x, y }};
   return a;
 }
};

If you don't have boost you can create your own array class or use std::tr1 if your compiler has it

template<typename T, std::size_t N>
struct array {
  T data[N];
};

That's all you need, but you can add the usual begin, end, size functions and so on to make it more comfortable to use.

like image 136
Johannes Schaub - litb Avatar answered Oct 06 '22 01:10

Johannes Schaub - litb


Unfortunately, there really is no proper, clean way to do this. Consider it something of a language limitation that results from an awkward mixing of C++ constructors and C style arrays. The C++11 standard addresses this issue, but until then you'll have to settle for a workaround.

Since A has no default constructor, one possible work-around is to have an array of A* pointers, and then loop over the array and initialize each one with new. (Obviously, don't forget to delete each item in the array in B's destructor, or just use smart pointers.)

like image 40
Charles Salvia Avatar answered Oct 06 '22 01:10

Charles Salvia


It should work in C++0x, but g++ 4.5.0 complains with "bad array initializer". If you replace A foo[2] with std::vector<A> foo, it compiles.

like image 39
fredoverflow Avatar answered Oct 06 '22 00:10

fredoverflow