[英]Why do C++ classes without member variables occupy space?
I found that both MSVC and GCC compilers allocate at least one byte per each class instance even if the class is a predicate with no member variables (or with just static member variables). 我发现MSVC和GCC编译器每个类实例至少分配一个字节,即使该类是没有成员变量的谓词(或只有静态成员变量)。 The following code illustrates the point.
以下代码说明了这一点。
#include <iostream>
class A
{
public:
bool operator()(int x) const
{
return x>0;
}
};
class B
{
public:
static int v;
static bool check(int x)
{
return x>0;
}
};
int B::v = 0;
void test()
{
A a;
B b;
std::cout << "sizeof(A)=" << sizeof(A) << "\n"
<< "sizeof(a)=" << sizeof(a) << "\n"
<< "sizeof(B)=" << sizeof(B) << "\n"
<< "sizeof(b)=" << sizeof(b) << "\n";
}
int main()
{
test();
return 0;
}
Output: 输出:
sizeof(A)=1
sizeof(a)=1
sizeof(B)=1
sizeof(b)=1
My question is why does compiler need it? 我的问题是为什么编译器需要它? The only reason that I can come up with is ensure that all member var pointers differ so we can distinguish between two members of type A or B by comparing pointers to them.
我能提出的唯一原因是确保所有成员var指针不同,这样我们就可以通过比较它们的指针来区分A或B类型的两个成员。 But the cost of this is quite severe when dealing with small-size containers.
但是在处理小型容器时,这个成本非常严重。 Considering possible data alignment, we can get up to 16 bytes per class without vars (?!).
考虑到可能的数据对齐,我们每个类最多可以获得16个字节而不需要vars(?!)。 Suppose we have a custom container that will typically hold a few int values.
假设我们有一个自定义容器,通常会包含一些int值。 Then consider an array of such containers (with about 1000000 members).
然后考虑一系列这样的容器(大约有1000000个成员)。 The overhead will be 16*1000000!
开销将是16 * 1000000! A typical case where it can happen is a container class with a comparison predicate stored in a member variable.
可能发生的典型情况是容器类,其中比较谓词存储在成员变量中。 Also, considering that a class instance should always occupy some space, what type of overhead should be expected when calling A()(value) ?
另外,考虑到类实例应该总是占用一些空间,在调用A()(value)时应该期望什么类型的开销?
It's necessary to satisfy an invariant from the C++ standard: every C++ object of the same type needs to have a unique address to be identifiable. 必须满足C ++标准中的不变量:相同类型的每个C ++对象都需要具有可识别的唯一地址。
If objects took up no space, then items in an array would share the same address. 如果对象没有占用空间,则数组中的项将共享相同的地址。
Basically, it's an interplay between two requirements: 基本上,它是两个要求之间的相互作用:
Note that the first condition alone does not require non-zero size: Given 请注意,仅第一个条件不需要非零大小:给定
struct empty {};
struct foo { empty a, b; };
the the first requirement could easily be met by having a zero-size a
followed by a single padding byte to enforce a different address, followed by a zero-size b
. 通过使用零大小
a
后跟单个填充字节来强制执行不同的地址,然后是零大小b
,可以轻松满足第一个要求。 However, given 但是,给定
empty array[2];
that no longer works because a padding between the different objects empty[0]
and empty[1]
would not be allowed. 这不再有效,因为不允许在不同对象之间填充
empty[0]
和empty[1]
。
All complete objects must have a unique address; 所有完整对象必须具有唯一的地址; so they must take up at least one byte of storage - the byte at their address.
所以它们必须占用至少一个字节的存储空间 - 它们的地址为字节。
A typical case where it can happen is a container class with a comparison predicate stored in a member variable.
可能发生的典型情况是容器类,其中比较谓词存储在成员变量中。
In this case, you can use the empty base class optimisation: a base subobject is allowed to have the same address as the complete object that it's part of, so can take up no storage. 在这种情况下,您可以使用空基类优化:允许基础子对象具有与其所属的完整对象相同的地址,因此不占用任何存储空间。 So you can attach the predicate to a class as a (perhaps private) base class rather than a member.
因此,您可以将谓词作为(可能是私有的)基类而不是成员附加到类。 It's a bit more fiddly to deal with than a member, but should eliminate the overhead.
处理比成员更加繁琐,但应该消除开销。
what type of overhead should be expected when calling A()(value) ?
调用A()(value)时应该期望什么类型的开销?
The only overhead compared to calling a non-member function will be passing the extra this
argument. 与调用非成员函数相比,唯一的开销是传递额外的
this
参数。 If the function is inlined, then this should be eliminated (as would be the case, in general, when calling a member function that doesn't access any member variables). 如果函数是内联的,则应该消除(通常情况下,调用不访问任何成员变量的成员函数时)。
There are already excellent answers that answer the main question. 已经有很好的答案回答了主要问题。 I would like to address the concerns you expressed with:
我想解决您表达的担忧:
But the cost of this is quite severe when dealing with small-size containers.
但是在处理小型容器时,这个成本非常严重。 Considering possible data alignment, we can get up to 16 bytes per class without vars (?!).
考虑到可能的数据对齐,我们每个类最多可以获得16个字节而不需要vars(?!)。 Suppose we have a custom container that will typically hold a few int values.
假设我们有一个自定义容器,通常会包含一些int值。 Then consider an array of such containers (with about 1000000 members).
然后考虑一系列这样的容器(大约有1000000个成员)。 The overhead will be 16*1000000!
开销将是16 * 1000000! A typical case where it can happen is a container class with a comparison predicate stored in a member variable.
可能发生的典型情况是容器类,其中比较谓词存储在成员变量中。
Avoiding the cost of holding A
避免持有
A
的成本
If all instances of a container depend on type A
, then there is no need to hold instances of A
in the container. 如果容器的所有实例都依赖于类型
A
,则不需要在容器中保存A
实例。 The overhead associated with the non-zero size of A
can be avoided by simply creating an instance of A
on the stack when needed. 通过在需要时在堆栈上简单地创建
A
的实例,可以避免与非零大小的A
相关联的开销。
Not being able to avoid the cost of holding A
无法避免持有
A
的成本
You may be forced to hold a pointer to A
in each instance of the container if A
is expected to by polymorphic. 如果预期
A
具有多态性,则可能会强制在容器的每个实例中保持指向A
的指针。 For such a containerthe cost of each container goes up by the size of a pointer. 对于这样的容器,每个容器的成本上升了指针的大小。 Whether there are any member variables in the base class
A
or not makes no difference to the size of the container. 基类
A
是否存在任何成员变量对容器的大小没有影响。
Impact of sizeof A
sizeof A
影响
In either case, the size of an empty class should have no bearing on the storage requirements of the container. 在任何一种情况下,空类的大小都应该与容器的存储要求无关。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.