在构造函数中初始化数组,而不使用默认构造函数或赋值

时间:2010-09-26 14:45:33

标签: c++ arrays constructor initialization default

考虑:

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 */
 {}
};

我期待这个工作,因为我在GCC4.3中使用C ++ 0x支持,据称支持初始化列表。没有快乐。

我有一个没有默认构造函数的A类。这是不容谈判的。默认情况下分配默认值不是一种选择。

我正在尝试创建使用A的B.B :: foo可能不是std :: vector。

如何在B::foo初始化B(...),只构建一次元素?

目前,我正在考虑用

取代B.
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) {}
};

甚至将char foo [2*sizeof(A)]与展示位置一起使用 - YUK!

当然有正确的方法吗?

4 个答案:

答案 0 :(得分:5)

您可以使用boost::array。它内部有一个普通的原生数组,因此它仍然具有与您的示例相同的内存布局。

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;
 }
};

如果你没有提升,你可以创建自己的array类,或者如果你的编译器有它,可以使用std::tr1

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

这就是您所需要的,但您可以添加常用的beginendsize功能等,以便使用起来更加舒适。

答案 1 :(得分:4)

不幸的是,确实没有正确,干净的方法来做到这一点。考虑一下C ++构造函数和C样式数组混乱的语言限制。 C ++ 11标准解决了这个问题,但在此之前,你必须解决这个问题。

由于A没有默认构造函数,因此一种可能的解决方法是使用A*指针数组,然后遍历数组并使用new初始化每个指针。 (显然,不要忘记在B的析构函数中使用delete数组中的每个项目,或者只使用智能指针。)

答案 2 :(得分:2)

它应该在C ++ 0x中工作,但g ++ 4.5.0抱怨“错误的数组初始化器”。如果您将A foo[2]替换为std::vector<A> foo,则会进行编译。

答案 3 :(得分:1)

您的问题与上一个问题相似:C++: constructor initializer for arrays

您的主要建议(让两位成员foo_afoo_b)可能是最好的做事方式,前提是您只需要两个元素。 除了初始化列表中类型的默认构造函数之外,没有办法初始化数组元素,正如您在示例中所做的那样。编辑:对不起,我没有看到您使用的是的C ++ 0x。在C ++ 0x中,您应该能够按照自己的意愿进行初始化,前提是A是可复制的或可移动的。不过,我不知道GCC 4.3对此的支持。

小心使用char数组和放置新的 - char数组未必正确对齐以构造A,这样做可能会导致未定义的行为。

其他一些建议:

  • 将指针数组存储到A或更好的智能指针数组,如auto_ptrboost::scoped_ptr,并使用new A(args...)在堆上创建A对象。
  • 存储另一种类型的数组,例如boost::optional<A>,它可以为您处理默认构造和对齐问题,但仍然基本上将A对象存储在B对象中。