C++:构造函数中的多维数组初始化

10
我想在C++中将一个大小固定的二维数组用作类成员。然而,在构造函数中初始化它时遇到了问题。
以下是我的尝试,但都没有成功:
1.)
class A {
 public:
  int a[2][2];
  A();
};

A::A() {
a = {{1,2},{2,4}};
}

输出结果: 错误:从初始化列表向数组赋值

2.)

class A {
 public:
  int a[2][2];
  A();
};

A::A() {
int b[2][2] = {{1,2},{2,4}};
a = b;
}
产生: 无效的数组赋值 3.)
class A {
 public:
  int **a;
  A();
};

A::A() {
int b[2][2] = {{1,2},{2,4}};
a = b;
}

输出:错误:无法将'int [2][2]'转换为'int **'进行赋值

我来自C语言的背景。我知道我可以使用std::vector,也知道这种方法的缺点,但由于这对我来说是一个练习,我想知道如何使用普通数组使它正常工作。我应该补充说明,我希望在以后处理这个数组。我想改变存储的值,但不想改变大小。也许这也很重要(我想在正确的位置加上const可能会有所帮助?)。

5个回答

11

如果您使用的是C++11,您可以在构造函数定义中使用以下语法:

A() : a{{1,2}, {3, 4}} {}

如果你没有C++11,你将需要继续使用过时的方式:

A() {
  a[0][0] = 1;
  // etc
}

第一个例子还使用了构造函数初始化列表,应该始终使用它来初始化成员,而不是在构造函数体中初始化它们。


1
据我所知,此处使用的语法是非标准的,属于 g++ 语言扩展。 - Cheers and hth. - Alf
@Cheersandhth.-Alf 请尝试使用“-pedantic-errors”标志编译此代码和您的代码,并且... - Constructor
@构造函数:我认为我的代码有问题,但是使用g++ 4.8.2和选项“-pedantic-errors”编译没有问题。然而,Visual C++ 2013报告“错误C2536:'A::A::m':不能为数组指定显式初始化程序”。因此,在实际意义上,C++11符号(如果它是标准的话,经过检查并找不到相反的语言)还不具备可移植性。 - Cheers and hth. - Alf
@Cheersandhth.-Alf 真的吗?g++ 4.8.1诊断它是带有-pedantic-errors的错误代码。 - Constructor
@Cheersandhth.-Alf,我看到VC++(即使是VC++2013)存在一个错误 - Constructor
显示剩余8条评论

2

构造函数中各种多维数组的示例:

// int array1[1];
A() : array1{0} {}

// int array2[2][2];
A() : array2{{0}} {}

// int array3[3][3][3];
A() : array3{{{0}}} {}

1

试一试,这适用于二维数组(标准C++中):

 class A {
 public:
  int a[2][2];
  A();
};


typedef struct{ int a[4]; } array_t;

A::A() {

 int at[2][2] = {{1,2},{2,4}};

*(array_t*)a = *(array_t*)at;

}

Ciao Angelo


我认为这个赋值操作是未定义行为,不过你可以通过使用memcpy或等效方法来解决这个问题。 - M.M
这种技术强制编译器对上述数组使用赋值运算符(适用于标准结构体)。当操作数的大小相等时,才有效。我使用这个例子展示了C语言类型转换的威力。然而,我接受您的评论,并将就此问题提出一个新问题,以便我们可以听取其他关于以上代码的意见。谢谢。 - AngeloDM
在你走得太远之前,UB就出现了。将结构体别名为int[2][2]是未定义的。(标准列出了哪些类型可以与哪些类型别名,而这不在列表中)。此外,at可能无法正确对齐array_t *(我必须检查对齐要求的措辞才能验证这一点)。 - M.M
欢迎您的评论,我修改了我的解决方案,请告诉我您是否认为新的解决方案更具可移植性。谢谢。 - AngeloDM

0

你的第一个变量非常接近正确的C++11语法:

A::A()
    : a{{1,2},{2,4}}
{
}

1
这是gcc GNU扩展。去掉外部括号。 - pmr
@pmr 谢谢。实际上那是一个打字错误。 :-) - Constructor

0
为了补充之前的回答(你们真快):
在第1和第2种情况下,您尝试的是数组赋值,这是不允许的,正如编译器所说;
但我想引起您对第三种情况的注意,这是一个严重的误解,特别是来自于您所说的C语言。
将指向本地变量的指针分配给a

只是为了我自己和完全理解的缘故:这样做会在构造函数结束后使 **a 成为 NULL,对吧?我在 C 方面也不是专家。 - ravenfrost
不,不是这样的。类比的情况是,b只存在于它被声明的地方(构造函数)内部,所以如果你取它的地址,在函数结束时,a仍然会保持它之前的值,但我们无法保证那个地址上会有什么。程序可能会将该地址用于其他目的。很可能,如果你稍后尝试在函数外部访问a指向的内容,会出现关于无效内存的错误,或者读取到一些不可靠的值。 - Kahler
好的,我现在明白了。谢谢您为我解惑。 - ravenfrost

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