Is there any extra cost of calling non-virtual base methods in virtual inheritance?

牧云@^-^@ 提交于 2020-01-03 02:41:12

问题


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.

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

Common part

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);
}

Now the difference part is here:

Code 1 (normal inheritance)

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

Code 2 (virtual inheritance)

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

Code 3 (multiple virtual inheritance)

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

Overall code here.

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

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.


回答1:


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. 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.

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

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

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.

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.

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.




回答2:


First, take a look at foo:

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

Since Base::size() is non virtual, there is no virtual dispatch overhead with p->size().

Next, look at how you invoke foo:

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

Here, you are taking the address of an instance whose type is known statically, i.e., given an instance of Derived, the compiler can statically determine how to convert that to a Base *. So, no matter how Derived inherits from Base, the compiler knows how to convert it.

You need an example with less type information available statically to measure the impact of virtual inheritance.



来源:https://stackoverflow.com/questions/9444003/is-there-any-extra-cost-of-calling-non-virtual-base-methods-in-virtual-inheritan

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!