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?
It should work in C++0x, but g++ 4.5.0 complains with "bad array initializer". If you replace
A foo[2]
withstd::vector<A> foo
, it compiles.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 ofA*
pointers, and then loop over the array and initialize each one withnew
. (Obviously, don't forget todelete
each item in the array in B's destructor, or just use smart pointers.)Your question is similar to this previous question: C++: constructor initializer for arrays
Your main suggestion (make two members
foo_a
andfoo_b
) is probably the best way of doing things, provided that you'll need only two elements.There's no way of initializing array elements with anything but the type's default constructor in an initializer list, as you're trying to do in your example.Edit: Sorry, I didn't see that you were using C++0x. In C++0x you should be able to initialize as you wanted to do, provided that A is copyable or movable. I don't know about GCC 4.3's support for this, though.Be careful using
char
arrays and placement new -char
arrays aren't necessarily aligned properly to construct anA
, and doing this can result in undefined behavior.Some other suggestions:
auto_ptr
orboost::scoped_ptr
, and create the A objects on the heap usingnew A(args...)
.boost::optional<A>
, which handles the default construction and the alignment problem for you, but still essentially stores the A objects inside the B object proper.You can use
boost::array
. It has a plain native array inside, so it still has the same memory layout like in your example.If you don't have boost you can create your own
array
class or usestd::tr1
if your compiler has itThat's all you need, but you can add the usual
begin
,end
,size
functions and so on to make it more comfortable to use.