如何在成员初始化列表中初始化数组成员

123
class C 
{
public:
 C() : arr({1,2,3}) //doesn't compile
{}
    /*
    C() : arr{1,2,3} //doesn't compile either
{}
    */
private:
 int arr[3];
};

我相信原因是数组只能使用=语法进行初始化,即:
int arr[3] = {1,3,4};

问题

  1. 我怎样才能做到我想做的事情(也就是,在构造函数中初始化一个数组(而不是在函数体中赋值))。这样做可能吗?
  2. C++03标准是否对在构造函数初始化器中初始化聚合体(包括数组)有特殊规定?或者上述代码的无效性是其他规则的必然结果?
  3. C++11的列表初始化是否解决了这个问题?

请注意,我不想使用std::array或其他容器来解决这个问题。


你是否也知道 boost 固定大小数组的存在,它们提供了构造函数? - Benoît
6
@Benoît:我是。但我需要了解普通数组的知识 :) - Armen Tsirunyan
8个回答

68
  1. 我要怎样做才能在构造函数中初始化数组(而不是在函数体内赋值)。这种情况是否可能?

可以。使用包含数组的结构体即可。你已经知道这一点,但我不明白问题出在哪里。这种方式使你可以在构造函数中初始化数组,而不需要在函数体中进行赋值操作。这就是 boost::array 所做的事情。

C++03标准文件对于在构造函数初始化器中初始化聚合体(包括数组)有特殊规定吗?或上面代码的无效性是由其他规则推导出来的?

初始化列表使用直接初始化。根据第8条的规则,禁止了这种情况。我不确定以下情况的具体情况,但某些编译器允许这种写法。

struct A {
  char foo[6];
  A():foo("hello") { } /* valid? */
};

详情请参见此GCC PR

C++0x初始化器列表是否解决了这个问题?

是的,它们解决了这个问题。但是,我认为你的语法无效。您必须直接使用大括号来触发列表初始化。

struct A {
  int foo[3];
  A():foo{1, 2, 3} { }
  A():foo({1, 2, 3}) { } /* invalid */
};

当我写下 char * const foo[6]; 类成员时,我偶然发现它在 C++11 中需要初始化才能编译。 - JATothrim

37

C++98没有直接语法来初始化数组,除了将其清零(或对于非POD元素,进行值初始化)。为此,您可以编写C(): arr() {}

我认为Roger Pate关于C++0x聚合初始化的所谓限制是错误的,但我懒得查证或核实,而且这并不重要,对吗?编辑:Roger说的是“C++03”,我误读成了“C++0x”。对不起,Roger。☺

您当前代码在C++98中的解决方法是将数组包装在一个struct中,并从该类型的静态常量初始化它。数据无论如何都必须驻留在某个地方。简单地说,它可以看起来像这样:

class C 
{
public:
    C() : arr( arrData ) {}

private:
     struct Arr{ int elem[3]; };
     Arr arr;
     static Arr const arrData;
};

C::Arr const C::arrData = {{1, 2, 3}};

我说0x有哪些限制? - Roger Pate
1
@Roger: "agrregate initialization ... doesn't fit in a ctor initializer". 只是检查C++0x草案N3126,* mem-initializer 的语法,在§12.5.2 / 1中,包括使用 braced-init-list *。 - Cheers and hth. - Alf
9
我的句子前两个单词是"In C++03, ..." - Roger Pate

9

解决方法:

template<class T, size_t N>
struct simple_array { // like std::array in C++0x
   T arr[N];
};


class C : private simple_array<int, 3> 
{
      static simple_array<int, 3> myarr() {
           simple_array<int, 3> arr = {1,2,3};
           return arr;
      }
public:
      C() : simple_array<int, 3>(myarr()) {}
};

4
  1. 不,很遗憾。
  2. 你不能按照你想要的方式进行初始化,因为语法不允许(详见下文)。你只能使用类构造函数的初始化方式,而且正如你所知,这种方式无法用于初始化数组中的每个项。
  3. 我认为是这样的,因为它们可以在许多有用的方面对初始化进行泛化。但我不确定具体细节。

在C++03中,聚合初始化仅适用于类似以下语法的情况,必须是单独的语句,并且不适合于构造函数初始化列表中。

T var = {...};

3
我发现这个问题非常有用,但是没有针对成员数组元素为没有默认构造函数并且具有删除复制/移动构造函数的对象的情况提供示例。换句话说,需要一个初始化成员数组而不进行不必要对象复制的示例。
例如,有以下类A:
class A {
  public:
    int v;
    A(int v) : v(v) { }
    A() = delete;
    A(A &&) = delete;
    A(const A &) = delete;
    A &operator =(A &&) = delete;
    A &operator =(const A &) = delete;
};

使用非默认构造函数进行原地初始化的示例代码如下:

class B {
  public:
    A a[3];
    B() : a { {1}, {2}, {3} } {}
};

1

以下内容是基于Windows平台使用C++17的实践:

文件 A.h

class A
{
  private:
    float arrayVar[3];
}

文件 A.cpp:

A::A() : arrayVar{ 0.0f, 0.0f, 0.0f } { }

1

怎么样?

...
  C() : arr{ {1,2,3} }
{}
...

?

在g++ 4.8上编译正常


这是标准的吗?你能引用相关条款吗? - Armen Tsirunyan
6
无法在 Visual C++ 上编译。 - sergiol

-5
你想在构造函数中初始化一个整数数组吗?将其指向一个静态数组即可。
class C 
{
public:
    int *cArray;

};

C::C {
    static int c_init[]{1,2,3};
    cArray = c_init;
}

3
这是一个不好的想法,因为如果你改变了那个数组,那么该类的所有实例都会受到影响。 - Morty

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接