【问题标题】:Initialize array in constructor without using default constructor or assignment在构造函数中初始化数组而不使用默认构造函数或赋值
【发布时间】:2011-04-17 10:20:15
【问题描述】:

考虑:

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(...) 中初始化B::foo,只构造一次它的元素?

目前,我正在考虑将 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!

肯定有合适的方法来做到这一点?

【问题讨论】:

  • 只是让您知道我使用“0101”按钮更好地格式化了您的代码块。

标签: c++ arrays constructor initialization default


【解决方案1】:

您可以使用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;
 }
};

如果您没有 boost,您可以创建自己的 array 类或使用 std::tr1(如果您的编译器有)

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

这就是你所需要的,但你可以添加常用的beginendsize 等函数,使其使用起来更舒适。

【讨论】:

  • +1 不错的解决方案。虽然它会调用 A 的复制构造函数 N 次,除非编译器支持 R 值构造函数。
  • @Charles 谢谢。尽管除了xya 的不可避免的副本之外,所涉及的每个副本都有资格被优化:(1)本地a 的副本到返回值,以及(2)返回值的临时副本进入foo
  • 好吧,如果 spraff 有一个支持 C++0x 的编译器,那不应该也有 std::array 吗?
【解决方案2】:

不幸的是,确实没有正确、干净的方法来做到这一点。将其视为某种语言限制,这是由于 C++ 构造函数和 C 样式数组的笨拙混合造成的。 C++11 标准解决了这个问题,但在此之前,您必须找到一种解决方法。

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

【讨论】:

  • 你读过spraff 写的“我在GCC4.3 中使用C++0x 支持,据称它支持初始化列表”
  • 我很确定 GCC 4.3 的 C++0x 扩展不支持初始化列表。见gcc.gnu.org/projects/cxx0x.html
【解决方案3】:

它应该在 C++0x 中工作,但 g++ 4.5.0 抱怨“错误的数组初始化程序”。如果将A foo[2] 替换为std::vector&lt;A&gt; foo,它将编译。

【讨论】:

  • 是的,这就是初衷。知道为什么会失败吗?
  • @spraff 收回我的评论。似乎它仅适用于非类元素类型,即使在 GCC4.6 上也是如此 :(
  • @spraff:对我来说听起来像是一个 g++ 错误。
【解决方案4】:

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

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

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

其他一些建议:

  • 存储指向 A 的指针数组,或者更好的是,存储一个智能指针数组,如 auto_ptrboost::scoped_ptr,并使用 new A(args...) 在堆上创建 A 对象。
  • 存储另一种类型的数组,例如 boost::optional&lt;A&gt;,它会为您处理默认构造和对齐问题,但本质上仍将 A 对象存储在 B 对象中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-16
    • 2014-07-25
    相关资源
    最近更新 更多