大小为0的对象

时间:2014-02-19 11:52:41

标签: c++

我知道C ++中的空类大小为1个字节。但是,我注意到sizeof()为此类的对象返回0(以g ++为单位):

    class Boom{
        int n[0];
    }

我可以为Boom对象打印有效的内存位置:

    Boom b;
    cout<<&b;

这个特定的内存位置是否被占用? 如果我稍后在程序中分配内存,是否有可能使用此位置?

5 个答案:

答案 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的对象远远超出标准。

Citation by Stroustroup

  

为什么空类的大小不为零?

     

确保两个不同对象的地址不同。出于同样的原因,“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是编译时操作符),该对象的变量在运行时也必须是可寻址的,因此占用内存中的空间。