类成员变量为什么可以是可变大小数组?为什么会编译通过?

10

我有这样一个情况,无法解释为什么它可以编译通过:

#include <iostream>
using namespace std;

class X {
public:
    X() {cout << "in X constructor: " << endl;};
};

class Y {
public:
    Y() {cout << "in Y constructor" << endl;};
private:    
    X x[];
};

int main() {
    Y y;
    return 0;
}

我正在定义一个变量大小的数组 X,作为类 Y 的成员。如果在类外部这样定义 X,肯定会导致编译错误,但是在类内部却不会。更重要的是,X 的构造函数从未被调用。
那么这里发生了什么?

2
这不是一个可变长度数组,而是一个“灵活的数组”。如果我没记错,在C语言中,这允许使用malloc技巧,通过“好看”的类似数组的接口将任意数量的数据附加到结构体上。在C++中,这是g++和clang++的GNU扩展。例如,请参见https://dev59.com/43VC5IYBdhLWcg3wlyIo。 - dyp
那个解释有什么问题:警告C4200:在结构体/联合中使用了非标准扩展:零大小数组? - knivil
@remyabel 当我在main()中编译int x[]时,我得到了编译错误:storage size of 'x' isn't known。因此,我认为int x[0]是一个大小为零的int数组。 - Davor Josipovic
5
编译器设置过于宽松:error: ISO C++ 禁止零大小数组 'x' [-pedantic] - juanchopanza
1个回答

13
C99标准6.7.2.1/16 (n1256)
作为一种特殊情况,具有多个命名成员的结构体的最后一个元素可以具有不完整的数组类型;这称为“柔性数组成员”。在大多数情况下,柔性数组成员将被忽略。特别地,结构体的大小就像省略了柔性数组成员一样,除了它可能有比省略所暗示的更多的尾部填充。
它不是可变长度数组。它不像数据成员,更像一个接口,通知编译器您可以通过柔性数组成员的名称访问某些内存。
/17

EXAMPLE After the declaration:

struct s { int n; double d[]; };

the structure struct s has a flexible array member d. A typical way to use this is:

int m = /* some value */;
struct s *p = malloc(sizeof (struct s) + sizeof (double [m]));

and assuming that the call to malloc succeeds, the object pointed to by p behaves, for most purposes, as if p had been declared as:

struct { int n; double d[m]; } *p;
C++11不允许此操作,但g++和clang++将其作为扩展接受。由于在C++中结构体的构造函数不知道元素数量,因此无法自动初始化这些元素。

我正在使用g++-std=c++11选项编译上述代码。 - Davor Josipovic
@davor "警告:ISO C++禁止零大小数组'x' [-Wpedantic]" - dyp
是的,我认为C++没理由不能初始化一个不完整类型的数组,但它们似乎在将[]转换为[0]后卡住了(这有点荒谬)。 - Potatoswatter
@dyp 抱歉,我还是没有完全理解。所有这些都与结构体和C语言有关。那么这一切如何转化为不属于C语言的类呢? - Davor Josipovic
@davor 它根本无法翻译!C++中没有灵活的数组成员。但是,g++和clang++允许它们作为扩展。在C++中,结构体和类基本上是相同的东西。 - dyp
显示剩余2条评论

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