我知道C ++中的空类大小为1个字节。但是,我注意到sizeof()为此类的对象返回0(以g ++为单位):
class Boom{
int n[0];
}
我可以为Boom对象打印有效的内存位置:
Boom b;
cout<<&b;
这个特定的内存位置是否被占用? 如果我稍后在程序中分配内存,是否有可能使用此位置?
答案 0 :(得分:8)
数组的大小不能为零。如果您的编译器允许您声明一个,那么该语言不会指定它的行为方式。
在这种情况下,使用这个编译器,确实看起来这允许两个对象占据相同的位置:
Boom b[2];
std::cout << &b[0] << ' ' << &b[1] << std::endl;
// Output: 0x7fffffb23fdc 0x7fffffb23fdc
但是其他编译器可能表现不同,或者只是拒绝无效声明(如果你指定-pedantic -Werror
就像GCC那样)。
答案 1 :(得分:5)
对于类和数组,大小为0无效。 C ++标准说:
Sizeof [expr.sizeof]
[...]派生类最多的大小应大于零[...]
和
数组 [dcl.array]
在声明T D中,D的格式为
D1 [ constant-expressionopt] attribute-specifier-seqopt
[...]如果存在常量表达式(5.19), 它应是一个整数常数表达式,其值应大于零[...]
如果您使用g ++打开-pedantic
,您将收到以下警告(或pedantic-errors
错误):
ISO C++ forbids zero-size array ‘n’
因此您的程序基本上无效,但可以通过编译器扩展编译为C ++标准(除非您关闭此扩展程序)。
注意:即使您的编译器可以为0
报告class
,也不会对class
的任何实例(a.k.a.对象)报告:
#include <iostream>
class Boom {
int n[0];
};
int main() {
std::cout << sizeof(Boom) << '\n'; // prints 0
std::cout << sizeof(Boom()) << '\n'; // prints 1
}
大小为0的对象远远超出标准。
为什么空类的大小不为零?
确保两个不同对象的地址不同。出于同样的原因,“new”总是返回指向不同对象的指针。考虑:
class Empty { }; void f() { Empty a, b; if (&a == &b) cout << "impossible: report error to compiler supplier"; Empty* p1 = new Empty; Empty* p2 = new Empty; if (p1 == p2) cout << "impossible: report error to compiler supplier"; }
有一条有趣的规则表明空基类不需要用单独的字节表示:
struct X : Empty { int a; // ... }; void f(X* p) { void* p1 = p; void* p2 = &p->a; if (p1 == p2) cout << "nice: good optimizer"; }
此优化是安全的,可能最有用。它允许程序员使用空类来表示非常简单的概念而不会产生开销。一些当前的编译器提供了这种“空基类优化”。
答案 2 :(得分:2)
这是一个g ++扩展; C ++标准不允许使用数组
0
元素。我认为这个扩展最初是
旨在使用不完整的数组类型作为最终的
元素在C99中有效,但在C99中,只有struct
才合法
包含多个成员。至于如果你发生了什么
声明一个Boom
的数组,你将不得不问g ++。 (C99避免
这个问题需要至少一个其他成员。)
此功能的唯一实际用途是可变长度 动态分配的对象,例如:
struct Array
{
size_t size;
int data[];
};
// ...
Array* p = (Array*)malloc(sizeof(Array) + n * sizeof(int));
p->size = n;
(这使用C标准语法。)
在C ++中,我们通常只使用std::vector
并完成
它
答案 3 :(得分:1)
在此定义中
class Boom{
int n[0];
}
有两个错误。:) 1.你忘了在结束括号后放一个分号。 2.数组的大小不能设置为零。
即使是空类的大小也不等于零。例如
struct A {};
std::cout << sizeof( A ) << std::endl;
将返回大于0的值。
答案 4 :(得分:0)
当您打印&b
时,会打印存储变量b
的地址。是的,这个位置将被该变量占用。即使编译期间对象的大小为零(请记住sizeof
是编译时操作符),该对象的变量在运行时也必须是可寻址的,因此占用内存中的空间。