C++虚函数表内存开销

Ste*_*art 13 c++ memory virtual

考虑:

class A
{
    public:
        virtual void update() = 0;
}

class B : public A
{
    public:
        void update() { /* stuff goes in here... */ }

    private:
        double a, b, c;
}

class C { 
  // Same kind of thing as B, but with different update function/data members
}
Run Code Online (Sandbox Code Playgroud)

我现在在做:

A * array = new A[1000];
array[0] = new B();
array[1] = new C();
//etc., etc.
Run Code Online (Sandbox Code Playgroud)

如果我调用sizeof(B),返回的大小是3个双成员所需的大小,加上虚函数指针表所需的一些开销.现在,回到我的代码,结果是'sizeof(myclass)'是32; 也就是说,我的数据成员使用24个字节,虚拟功能表使用8个字节(4个虚函数).我的问题是:有什么办法可以简化这个吗?我的程序最终会使用大量的内存,我不喜欢它的25%被虚拟函数指针吃掉的声音.

Pon*_*ing 43

v表是每个类而不是每个对象.每个对象只包含一个指向其v表的指针.因此每个实例的开销是sizeof(pointer)(通常是4或8个字节).对于类对象的大小,您有多少虚函数无关紧要.考虑到这一点,我认为你不应该太担心它.


CB *_*ley 11

通常,具有至少一个虚函数的类的每个实例都将具有与其显式数据成员一起存储的额外指针.

没有办法解决这个问题,但请记住(通常也是)每个虚拟函数表在类的所有实例之间共享,因此一旦你支付了"vptr",就没有很多开销来拥有多个虚函数或额外的继承级别.税"(vtable指针的小成本).

对于较大的类,开销变得比例小得多.

如果你想要像虚拟函数那样做的功能,你将不得不以某种方式为它付费.实际上使用本机虚拟功能可能是最便宜的选择.


Rol*_*ien 6

你有两个选择.

1)不要担心.

2)不要使用虚函数.但是,不使用虚函数只需将大小移动到代码中,因为代码变得更复杂.


Nik*_*sov 6

vtable的空间成本是一个指针(模数对齐).表本身不会放在类的每个实例中.

  • 如果您的类大小小于vtable指针,那么对齐问题仍然存在.说`struct C {char c; 可能大小为1,任何这样的数组都会将它们打包紧密.如果你添加一个虚拟成员,在32位平台上它可能会将生成的5个存储字符填充到8,所以现在你突然每个对象浪费3个字符. (3认同)

Mar*_*ork 5

远离对象中vtable指针的非问题:

您的代码还有其他问题:

A * array = new A[1000];
array[0] = new B();
array[1] = new C();
Run Code Online (Sandbox Code Playgroud)

你遇到的问题是切片问题.
你不能把B类的一个对象到空间类A的对象保留的大小
你只切片B(或C)对象的一部分擦去留给你的只是一部分.

你想做什么.有一个A指针数组,以便它通过指针保存每个项目.

A** array = new A*[1000];
array[0]  = new B();
array[1]  = new C();
Run Code Online (Sandbox Code Playgroud)

现在你有另一个破坏问题.好.这可能会持续很长时间.
简短回答使用boost:ptr_vector <>

boost:ptr_vector<A>  array(1000);
array[0] = new B();
array[1] = new C();
Run Code Online (Sandbox Code Playgroud)

永远不要像这样分配数组,除非你必须(它太Java喜欢有用).

  • 严格来说,原始版本甚至不会编译.当数组元素不是指针时,它会尝试将*pointer*值赋给数组元素.在代码变得可编译之前声称它具有"切片问题"为时尚早. (4认同)