为什么C ++中的析构函数会增加它们所在对象的大小?

时间:2014-07-11 18:45:36

标签: c++ destructor

我知道这可能听起来像一个奇怪的问题,但我只是想知道C ++中的类是否比具有相同数据字段的结构更重要,而且这一件事我无法找到回答...
考虑一下:

struct SomeStruct {
    int a;
    int b;
};

class SomeClass {
public:
    SomeClass():a(0),b(0){}
private:
    int a;
    int b;
};

int main() {
    std::cout<<sizeof(SomeStruct)<<std::endl; // output is 8
    std::cout<<sizeof(SomeClass)<<std::endl; // output is 8
}

但是现在看看当我向SomeClass添加析构函数时会发生什么:

struct SomeStruct {
    int a;
    int b;
};

class SomeClass {
public:
    SomeClass():a(0),b(0){}
    virtual ~SomeClass(){}
private:
    int a;
    int b;
};

int main() {
    std::cout<<sizeof(SomeStruct)<<std::endl; // output is 8 bytes
    std::cout<<sizeof(SomeClass)<<std::endl; // output is 16 bytes!
}

为什么SomeClass需要8个字节用于析构函数?

3 个答案:

答案 0 :(得分:17)

尺寸增加是因为virtual。如果你没有使析构函数虚拟化,你就不会看到大小的增加。

所以,不是析构函数会让你的类型更大,而是它添加了一个虚拟函数来执行它。

有问题的8个额外字节是指向您正在使用的类的虚拟表(vtable)的指针。正如评论中所指出的,这是一次&#34;一次&#34;成本。向一个类添加一个虚拟功能会带来这个成本,但是你不会看到带有额外虚拟功能的成本。

编辑:

类中的附加大小取决于它是编译为32位还是64位程序。虚拟表的链接在32位上额外增加4个,在64位平台上增加8个额外字节。

答案 1 :(得分:4)

这不是你添加了析构函数的事实。事实上,您添加了一个虚拟方法(其他虚拟方法不会产生额外的每个实例成本)。大多数(所有?)C ++实现使用虚函数指针表来启用动态调度,这需要指向相应表的指针存储在每个对象中。这个指向虚拟表的指针是你看到的每个对象的额外空间。

答案 2 :(得分:0)

当您将析构函数声明为虚拟时,编译器会自动将vtable指针添加为您的类中的成员。这是必要的,因此它可以找到从您的派生类派生的所有析构函数的地址。

这个新成员(你不能轻易访问,你也不应该这样)被添加到你的类中,因此通过一个简单的原始指针的大小增加它的大小,这通常与int的大小相同,但可能取决于你的架构。