C++ 为什么只有在';谁分配了堆?

C++ 为什么只有在';谁分配了堆?,c++,arrays,C++,Arrays,我注意到不允许创建长度为零的非堆分配数组 // error: cannot allocate an array of constant length zero char a[0]; // this is okay though char *pa = new char[0]; 我还注意到,它可以创建长度为零的堆分配数组 // error: cannot allocate an array of constant length zero char a[0]; // this is okay t

我注意到不允许创建长度为零的非堆分配数组

// error: cannot allocate an array of constant length zero
char a[0];
// this is okay though
char *pa = new char[0];
我还注意到,它可以创建长度为零的堆分配数组

// error: cannot allocate an array of constant length zero
char a[0];
// this is okay though
char *pa = new char[0];

我想它们都有标准的保证(我手头没有标准的副本)。如果是,为什么它们如此不同?为什么不允许在堆栈上设置零长度数组(或者反之亦然)?

这是在C++标准的以下章节中讨论的。 3.7.3.1/2:

(32)意图是通过调用<代码> MARROCK()/<代码>或<代码> CalOrthe()/代码>实现操作符>代码>(或)代码,因此规则基本相同。C++在要求零空指针返回零请求时与C不同。 而且

5.3.4,第7段

当直接新声明符中表达式的值为零时,将调用分配函数来分配不含元素的数组


C++中不允许0大小的数组:

8.3.4/1:

“如果存在
\u常量表达式+
(5.19),则该表达式应为积分常量表达式,且其值应大于零。”

我理解,这背后的原理似乎是C++标准要求每个对象都必须有唯一的地址(这就是为什么一个空类对象的大小为1)的原因。因此,无需向其提供地址,因此无需首先允许其使用



就c而言,零长度数组是,通常通过将零长度数组放置在结构的末尾来实现具有可变大小的结构。如果我的内存是正确的,它通常被称为C struct Hack

,这取决于编译器实现/标志。Visual C++不允许,GCC允许(不知道如何禁用)。 使用这种方法,静态_断言可以在VC中实现,但不能在GCC中实现:

#define STATIC_ASSERT(_cond) { char __dummy[_cond];}

即使凭直觉,这也是有道理的

由于heap-allocated方法在堆栈上创建指向堆上分配的内存块的指针,因此它仍然在“创建一些”大小的东西:
sizeof(void*)
。在分配零长度数组的情况下,堆栈上存在的指针可以指向任何地方,但没有意义


相反,如果在堆栈上分配数组,则有意义的零长度数组对象会是什么样子?它真的没有意义。

0长度数组不是很有用。当你在计算 维度,它可能会发生,并且不必处理该情况非常有用 特别是在你的代码中。在
new
之外,数组的维度 必须是常量,而不是计算值,如果您知道 常数是0,为什么要定义它

至少,这是我(从工作人员那里)听到的理由 它)。我并不完全相信:在代码中不得不这样做并不罕见 使用值未知的符号常量(从标头) 文件,甚至命令行)。因此,这可能是有意义的 允许0个元素的数组。过去至少有一个编译器 允许他们,尽管我忘了是哪一个

< > C++中的一个常见技巧是在编译时使用这样的数组。 断言,类似于:

char dummyToTestSomeSpecificCondition[ condition ];
char dummyToTestSomeSpecificCondition[ 2 * condition - 1 ];
如果条件为false,则编译失败;如果条件为false,则编译失败 事实并非如此。除了一个编译器(如果它仍然存在);我会用 比如:

char dummyToTestSomeSpecificCondition[ condition ];
char dummyToTestSomeSpecificCondition[ 2 * condition - 1 ];

,以防万一。

我认为他们行为不同的主要原因是第一个:

char a[0];
是一个大小为0的数组,这是禁止的,因为它的大小应该是定义为0×sieof(char),而在C或C++中,不能定义大小0的类型。 但第二点:

char *pa = new char[0];
不是真正的数组,它只是一个由0个char类型的对象组成的块,放在内存中。由于0个对象的序列可能有用,因此这是允许的。它只返回一个指针,指针经过最后一项,这是非常好的

在我的论点中,考虑下面的例子:

new int[0][3]; //ok: create 0 arrays of 3 integers
new int[3][0]; //error: create 3 arrays of 0 integers

尽管这两行将分配相同的内存(0字节),但一行是允许的,另一行不是。

堆上的零长度数组是一个太小的jar,无法容纳任何内容。堆栈上的零长度阵列就像水箱中两加仑水之间的空间…:)静态断言通常使用负数实现。VisualC++专门允许零大小的数组,尽管警告是“非标准扩展”。VC++不允许使用零大小的本地数组。实际上,我的主要问题是,为什么它们在上述两种情况下不同?@Eric:请检查更新的答案。它试图回答你的问题。这没有道理。堆栈上没有指针,并且
malloc
new
返回的指针与分配的内存无关。@詹姆斯:那么谁持有
new
malloc
分配的内存区域的地址?@J调用它们的客户端。(或者在内存泄漏的情况下,没有人。)@James:显然是的。但实际地址存储在内存中的什么地方呢?在某个地方,必须记录堆分配内存的地址。此地址存储在堆栈上的指针中@或者在静态变量中,或者在另一个动态分配的对象中,或者,如果程序员不小心的话,一点也不。