我创建了一个类,但它的大小为零。现在,我怎样才能确定所有对象都有不同的地址? (我们知道,空类的大小不为零。)
#include<cstdio>
#include<iostream>
using namespace std;
class Test
{
int arr[0];//Why is the sizezero?
};
int main()
{
Test a,b;
cout <<"size of class"<<sizeof(a)<<endl;
if (&a == &b)// now how we ensure about address of objects ?
cout << "impossible " << endl;
else
cout << "Fine " << endl;//Why isn't the address the same?
return 0;
}
答案 0 :(得分:8)
您的班级定义是非法的。 C ++不允许在任何上下文中使用大小为0
的数组声明。但即使您将类定义完全清空,仍然需要sizeof
来计算非零值。
9/4类类型的完整对象和成员子对象应具有 非零大小。
换句话说,如果您的编译器接受类定义并将上面的sizeof
计算为零,那么该编译器将超出标准C ++语言的范围。它必须是与标准C ++无关的编译器扩展。
因此,在这种情况下,“为什么”问题的唯一答案是:因为这是在编译器中实现的方式。
我不知道与确保不同对象具有不同地址有什么关系。无论对象大小是否为零,编译器都可以轻松地强制执行此操作。
答案 1 :(得分:6)
标准规定,拥有零大小的数组会导致未定义的行为。当您触发未定义的行为时,标准提供的其他保证(例如要求对象位于不同的地址)可能无法保留。
不要创建零大小的数组,并且不应该有这个问题。
答案 2 :(得分:4)
这在很大程度上是对其他答案已经说过的重复,但是有一些对ISO C ++标准的引用以及关于g ++奇怪行为的一些思考。
ISO C ++ 11标准,在第8.3.4节[dcl.array]第1段中说:
如果存在常量表达式(5.19),则它应为a 积分常数表达式及其值应大于零。
您的班级定义:
class Test
{
int arr[0];
};
违反此规则。第1.4节[intro.compliance]适用于此:
如果程序包含违反任何可诊断规则的行为,... 符合要求的实施应至少发布一条诊断信息。
据我了解,如果编译器发出此诊断信息然后接受该程序,则程序的行为是未定义的。所以这是关于你的计划的所有标准。
现在它成了关于编译器的问题,而不是关于语言的问题。
我正在使用g ++版本4.7.2,它允许将零大小的数组作为扩展名,但如果您使用-std=c++11 -pedantic
调用它,则会打印所需的诊断(警告):
warning: ISO C++ forbids zero-size array ‘arr’ [-pedantic]
(显然你也在使用g ++。)
实验表明,g ++对零大小数组的处理有点奇怪。这是一个基于程序中的例子的例子:
#include <iostream>
class Empty {
/* This is valid C++ */
};
class Almost_Empty {
int arr[0];
};
int main() {
Almost_Empty arr[2];
Almost_Empty x, y;
std::cout << "sizeof (Empty) = " << sizeof (Empty) << "\n";
std::cout << "sizeof (Almost_Empty) = " << sizeof (Almost_Empty) << "\n";
std::cout << "sizeof arr[0] = " << sizeof arr[0] << '\n';
std::cout << "sizeof arr = " << sizeof arr << '\n';
if (&x == &y) {
std::cout << "&x == &y\n";
}
else {
std::cout << "&x != &y\n";
}
if (&arr[0] == &arr[1]) {
std::cout << "&arr[0] == &arr[1]\n";
}
else {
std::cout << "&arr[0] != &arr[1]\n";
}
}
我在int arr[0];
上收到了所需的警告,然后是以下运行时输出:
sizeof (Empty) = 1
sizeof (Almost_Empty) = 0
sizeof arr[0] = 0
sizeof arr = 0
&x != &y
&arr[0] == &arr[1]
C ++要求一个类(即使没有成员的类)的大小至少为1个字节。 g ++遵循此类Empty
的要求,该类没有成员。但是为类添加一个零大小的数组实际上会导致类本身的大小为0。
如果声明两个类型为Almost_Empty
的对象,则它们具有不同的地址,这是明智的;编译器可以按照自己喜欢的方式分配不同的对象。
但对于数组中的元素,编译器的灵活性较低:N个元素的数组必须的大小为元素数的N倍。
在这种情况下,由于类Almost_Empty
的大小为0,因此Almost_Empty
元素的数组大小为0 *,并且此类数组的所有元素具有相同的地址
这并不表示g ++不符合C ++标准。它通过打印诊断来完成它的工作(即使它是一个非致命的警告);之后,就标准而言,它可以随意做任何事情。
但我可能会认为这是g ++中的一个错误。就常识而言,在类中添加一个空数组不应该使类变小。
但是有一个理由。正如DyP在评论中指出的那样,gcc手册(包含g ++)mentions this feature作为C扩展名also available for C++。它们主要用作结构的最后一个成员,它实际上是一个可变长度对象的头。这被称为struct hack。它在C99中由灵活的数组成员替换,在C ++中由容器类替换。
我的建议:不要定义零长度数组,避免所有这些混乱。如果您确实需要可以为空的元素序列,请使用其中一个C ++标准容器类,例如std::vector
或std::array
。
答案 3 :(得分:1)