声明的数组数据成员没有大小

Array data members declared with no size

本文关键字:数据成员 数组 声明      更新时间:2023-10-16

我正在努力了解数组在C++中是如何工作的。SO上有一些不错的线索,但有一个问题我找不到答案:

为什么可以声明没有大小的数组数据成员?我认为在C++中,数组大小必须是编译时常数?

示例:

#include<iostream>
class Object{
public:
      Object(std::size_t n){  
        for(std::size_t i = 0; i<n; ++i) { array[i] ='X'; }
        //prints 0 because 'sizeof' is compile-time operator
        std::cout << "compile-time size: " << sizeof(array) << std::endl;
        std::cout << "run-time size " << n << std::endl;
      }
private:
      char array[];
};  
int main( int argc, char** argv )
{
  Object obj(10);      //10 chars
  std::size_t n;
  std::cin >> n;
  Object obj2(n);      //n chars in automatic storage i.e. on the stack??
}
Input: 
  n = 1000
Output: 
  compile-time size: 0
  run-time size 10
  compile-time size: 0
  run-time size 1000

这是否意味着obj2的数组数据成员存储在自动存储中,但大小是在运行时动态确定的?

感谢

为什么可以声明没有大小的数组数据成员?

在标准C++中,它不是。在C中,你可以在结构的末尾放一个,以允许一个可变大小的数组,但你必须确保为你想要使用的任何大小分配足够的存储空间。某些C++编译器可能允许将其作为非标准扩展。

这是否意味着obj2的数组数据成员存储在自动存储中,但大小是在运行时动态确定的?

不,这意味着阵列没有任何存储空间,而您正在重写堆栈的其他部分。这不是个好主意。

如果需要动态数组,请使用std::vector

根据C++标准(9.2类成员)

9非静态(9.4)数据成员不应具有不完整的类型。在里面特别是,C类不应包含类的非静态成员C、 但是它可以包含指向C类对象的指针或引用。

所以它要么是编译器的特性,要么就是它的bug。

作为类的非静态数据成员的数组存储在分配该类的相应对象的位置。

对于C,则C允许定义结构的柔性阵列成员。

来自C标准(6.7.2.1结构和并集规范)

18作为一种特殊情况,结构的最后一个元素一个命名成员可能具有不完整的数组类型;这被称为柔性阵列成员

但在这种情况下,结构应具有多个命名成员

C99允许一个名为灵活数组成员的功能。这在C11标准的§6.7.2.11/18中有描述:

作为一种特殊情况,具有多个的结构的最后一个元素命名成员可能具有不完整的数组类型;这被称为柔性阵列构件。在大多数情况下,柔性阵列成员被忽略。

它们不是C++的一部分,但一些编译器允许将它们用作扩展。例如,GCC在其C扩展页面上明确指出了这一点:

ISO C99中的一些特性,但不是C90或C++中的特性,如GCC在C90模式和C++中接受的扩展。

为了兼容性,Clang通常实现GNU扩展。请注意,在所述成员上使用sizeof似乎是GCC错误或扩展:

灵活数组成员的类型不完整,因此运算符可能不适用。作为原始实现的一个怪癖对于长度为零的数组,sizeof的计算结果为零。

此外,作为类中唯一数据成员的灵活数组成员是GNU扩展。

不可能char数组[]和指向char的指针相同。这意味着你可以做到这一点。

char* pointer;
char array[];
array=pointer;

指针具有值,该值在创建指针时在内存中。简单地指向记忆中的某个地方
数组的工作方式与指针相同。如果int有4个字节,则array[5]指向指针字节后的int 5*4=20。

int array[];
array[5];
*(array+5);

C++在遍历数组后不会抛出异常。通常程序会崩溃,因为默认情况下指针指向程序内存之外的某个位置。

将测试移到从main()调用的新函数中,然后应该会看到堆栈粉碎。