在虚拟继承中调用非虚拟基本方法有额外的成本吗? [英] Is there any extra cost of calling non-virtual base methods in virtual inheritance?

查看:146
本文介绍了在虚拟继承中调用非虚拟基本方法有额外的成本吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我曾经提到此问题(我更改了标题)。我知道与 virtual ness相关的代码生成是特定于实现的。然而,早期的问题表明,当调用非虚拟基本方法时,与 virtual 继承有关的额外成本。

I had referred this question (I changed its title). I am aware that code generation related to virtualness are implementation specific. However, earlier question suggests that, there is an additional cost related to virtual inheritance, when calling non-virtual base method.

我写了以下测试代码,并在g ++中检查其汇编( -O4 ):

I wrote following test codes and checked its assembly in g++ (with -O4):

struct Base {
  int t_size;
  Base (int i) : t_size(i) {}
  virtual ~Base () {}
  int size () const { return t_size; };
};

struct D1 : virtual Base {
  int a[10];
  D1 () : Base(0) {}
  ~D1 () {}
};
struct D2 : virtual Base {
  int a[20];
  D2() : Base(0) {}
  ~D2 () {}
};

...

void foo (Base *p) 
{
  if(p->size())
    return;
  p = 0;
}

int main ()
{
  Derived d;
  foo(&d);
}

现在差异部分在这里:

struct Derived : Base {
  Derived () : Base(0) {}
  ~Derived () {}
  int a[100];
};



代码2(虚拟继承)



Code 2 (virtual inheritance)

struct Derived : virtual Base {
  Derived () : Base(0) {}
  ~Derived () {}
  int a[100];
};



代码3(多重虚拟继承)



Code 3 (multiple virtual inheritance)

struct Derived : D1, D2 {
  Derived () : Base(0) {}
  ~Derived () {}
  int a[100];
};

Overall code here.

当我检查它的程序集时,所有3个版本之间没有区别。以下是汇编代码:

When I checked its assembly, there is no difference between all 3 versions. And following is the assembly code:

        .file   "virtualInheritFunctionCall.cpp"
        .text
        .p2align 4,,15
        .globl  _Z3fooP4Base
        .type   _Z3fooP4Base, @function
_Z3fooP4Base:
.LFB1:
        .cfi_startproc
        rep 
        ret 
        .cfi_endproc
.LFE1:
        .size   _Z3fooP4Base, .-_Z3fooP4Base
        .section        .text.startup,"ax",@progbits
        .p2align 4,,15
        .globl  main
        .type   main, @function
main:
.LFB2:
        .cfi_startproc
        xorl    %eax, %eax
        ret 
        .cfi_endproc
.LFE2:
        .size   main, .-main
        .ident  "GCC: (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1"
        .section        .note.GNU-stack,"",@progbits

virtual 继承没有任何额外的成本,当某些优化开启?我需要执行任何更复杂的测试代码来评估这个吗?请注意,没有优化,这些程序集之间就有差别。

Does it mean that virtual inheritance doesn't have any extra cost, when certain optimization is ON ? Do I need to perform any more complex test code to evaluate this ? Note that, without optimization, there is a difference between these assemblies.

推荐答案


我想知道虚拟继承如何处理非虚拟基础方法

Rather than performance, I want to know how the virtual inheritance deals with non-virtual base methods

显然,它会调整 或类指针,然后将其传递给原方法。

Obviously, it will adjust this or class pointer then pass it to original method.

如果您以这种方式调整第三个示例,您可能可以观察到开销:

You might be able to observe overhead if you adjust 3rd example this way:


  1. 向Base,D1和D2添加虚拟方法(非重叠名称)。

  2. 将非重叠数据字段/成员变量(不重叠,不同的名称)添加到Base,D1,D2和派生。

  3. 向D2中添加非虚方法,该方法对D2和Base中的数据字段起作用。

  4. 将非虚方法添加到对D1和Base中的数据字段执行操作的D1。

  5. 将非虚拟方法添加到Derived,然后在D2和D1中调用上述非虚拟方法,然后对D2,D1,Base和Derived中的数据字段进行操作。

  6. 调查反汇编。

  1. Add virtual methods (non-overlapping names) to Base, D1 and D2. This will cause compiler to create virtual method tables.
  2. Add non-overlapping data fields/member variables (non-overlapping, different names) to Base, D1, D2 and derived.
  3. Add non-virtual method to D2 that operates on data fields in D2 and Base.
  4. Add non-virtual method to D1 that operates on data fields in D1 and Base.
  5. Add non-v\irtual method to Derived that calls aforementioned non-virtual methods in D2 and D1 then operates on data fields in D2, D1, Base and Derived.
  6. Investigate disassembly.

此外,一旦有一些成员变量,在调试器中调查生成的Derived类的布局。

Also, once there are some member variables, you might want to investigate layout of resulting Derived class in debugger.


当我检查其程序集时,所有3个版本之间没有区别

When I checked its assembly, there is no difference between all 3 versions

继承(虚拟或非虚拟)可能会增加一点差异,编译器可能会决定调整指针时将其从Derived *转换为Base *(或 this 如果基本非虚方法从派生方法调用)或vfptr。这将导致在将 this 或指针传递给函数/方法之前将一些值添加到当前值。

Inheritance (virtual or not) might add a little difference in a sense that compiler might decide adjust pointer to class when converting it from Derived* to Base* (or this if base non-virtual method is called from derived method) or vfptr. This will result in adding some value to current value of this or pointer before passing it to function/method.

但是,这最有可能在调用函数调用时完成,并且很可能仅在涉及多重继承时才会发生(因为可能有多个一个虚拟方法表)。也就是说如果你让继承类 A B 的类 C 它们都有虚方法,但没有共同的祖先,那么当你调用属于 A C 的方法可能在反汇编中看到指针调整。但是就是这样。这种开销的成本将会非常小。

However, this most likely will be done at the point when function call is invoked and it most likely will occur only when multiple inheritance is involved (because there might be more than one virtual method table). I.e. if you make class C that inherits classes A and B and they all have virtual methods, but no common ancestors, then when you call method that belongs to A from C you might see pointer adjustments in disassembly. But that's it. the cost of such overhead will be ridiculously small.

请注意,这是编译器特定的问题,我在这里写的一切都是基于对微软编译器的观察。也就是说它是无证的功能,因此,如果你担心性能,你应该使用profiler,而不是试图猜测性能的影响。主要优先级应该是代码可读性。

Please note that this is compiler-specific question, and everything i've written here is based on observation of microsoft compiler. I.e. it is "undocumented feature", as a result, if you worry about performance, you should use profiler instead of trying to guess performance impact. Main priority should be code readability anyway.

这篇关于在虚拟继承中调用非虚拟基本方法有额外的成本吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆