静态成员变量对对象大小有什么影响?

18

我想知道在诸如C++之类的语言中,静态成员变量通常是如何实现的,以及它们的使用是否会影响实例化对象的大小。

我知道静态成员由该类的所有实例共享,但它是如何共享的呢?如果它影响对象大小,那么有10个静态变量比1个静态变量增加的大小更多吗?

我之所以问这个问题,是因为我能想到两种实现方式:

  • 向每个对象添加指向静态数据的指针,类似于某些实现添加指向虚函数表的指针
  • 直接引用静态数据,就像全局变量一样,偏移量由链接器/加载器解析

1
这是一种你可以轻松测试的问题。只需创建适当的类并执行sizeof(T),它将告诉你它们有多大。 - Martin York
据我所知,Java中没有sizeof运算符。 - Robert S. Barnes
2个回答

31
在C++中,静态成员不属于类的实例。它们甚至不会使实例和类的大小增加1个比特!
struct A
{
    int i;
    static int j;
};
struct B
{
    int i;
};
std::cout << (sizeof(A) == sizeof(B)) << std::endl;

输出:

1
那就是说,AB 的大小完全相同。静态成员更像是通过 A::j 访问的全局对象。
请在 ideone 查看演示:http://www.ideone.com/YeYxe 来自 C++ 标准(2003)的 $9.4.2/1:
静态数据成员不是类的子对象的一部分。 有且仅有一个静态数据成员副本由该类的所有对象共享。
来自标准的 $9.4.2/3 和 7:
静态数据成员被定义后,即使没有创建其类的任何对象,它也存在。 静态数据成员的初始化和销毁与非局部对象(3.6.2、3.6.3)完全相同。
正如我所说,静态成员更像是全局对象!

4
静态变量不是对象本身的一部分,因此不应像对象一样进行序列化处理。 - Vinay Pai
1
@Nerian:序列化还取决于您想在序列化对象中包含哪些成员,以及不包含哪些成员。由于静态成员不属于类的实例,因此您很可能也不想对其进行序列化;它们更像是使用A::j访问的全局对象。无论如何,请不要相信我的意见。我对序列化了解不多。请咨询一些了解的人,并开始另一个话题。 :-) - Nawaz
1
+1:对于ideone.com的链接,这是我第一次看到。非常酷! - Robert S. Barnes
@Nawaz:我不确定你是否能够参考标准中的任何段落?还是说这纯粹是一个实现细节,恰好99%的时间以相同的方式实现? - Robert S. Barnes
3
这可以从POD类型的定义中推断出来;标准仔细地声明添加“static”成员不能将POD类型转变为非POD类型。而且,POD类型的内存布局是严格定义的。 - anatolyg
显示剩余8条评论

6

静态成员在编译时由编译器解析。从底层来看,静态变量与全局变量没有什么不同。它们之间的区别只在于您在代码中如何引用它们、它们可见的范围以及它们何时以及如何初始化。


请问您能否添加一个参考资料的链接,以进一步解释您的答案? - David Weiser
2
@David:我不是Vinay,但我不确定什么样的参考资料可以解决这个问题。我认为Vinay的答案最好的支持方式是C++和Java语言规范中没有涉及静态变量会对类实例造成运行时开销的内容,因此它们不会产生这种开销。 - Dan Breslau

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接