In a TU like this
#include "Foo.hpp"
int main() {
// stuff
Foo* foo{new Foo{}};
foo->foo();
// stuff
}
where Foo.hpp contains
#pragma once
struct Foo {
virtual void foo(); // implmented somewhere
};
no call to anything other than Foo::foo can happen, right? foo is virtual and nor it nor the class are final, so yes, in another TU there could be objects of derived classes that override foo, and so on, but... as far as this TU is concerned I think it's pretty clear that foo->foo() calls Foo::foo(). I don't see how it could be otherwise.
Then why is the generated assembly like this?
main: # @main
push rax
mov edi, 8
call operator new(unsigned long)@PLT
mov rcx, qword ptr [rip + vtable for Foo@GOTPCREL]
add rcx, 16
mov qword ptr [rax], rcx
mov rdi, rax
call Foo::foo()@PLT
xor eax, eax
pop rcx
ret
I don't really understad it in detail, but I clearly read vtable. Why is it even there?
I'd have expected the assembly of the TU above to be the same as the one I get if I remove the virtual keyword:
main: # @main
push rax
mov edi, 1
call operator new(unsigned long)@PLT
mov rdi, rax
call Foo::foo()@PLT
xor eax, eax
pop rcx
ret
From this other answer I read that
A* a = new B; a->func();In this case the compiler can determine that
apoints to aBobject and, thus, call the correct version offunc()without dynamic dispatch. […] Of course, whether compilers do the corresponding analysis depends on its respective implementation.
Is the answer simply that Clang does not make the analysis that would allow to deduce that no runtime dispatch is needed?
Or am I missing something? Maybe I'm simply totally misunderstanding the assembly?
This line
initialises the vtable pointer.
The vtable mechanism is not used to call
Foo::foo, however each object that has a vtable needs to have its vtable pointer initialised. If you don't initialise the vtable pointer of theFooobject,Foo::foo()may break (for example, it can try anddynamic_castthis).If you give
Foo::fooan inlinable body, the compiler may (or may not) optimise away the entireFooobject, depending on what exactly is in the body. However it is unlikely that the compiler will allow an object with uninitialised vtable pointer to exist. It is just too much trouble and not worth the effort to handle this fringe case.