Can C++11’s final qualifier affect codegen?

To satisfy my curiosity, I compiled this

struct A { void f(); };
struct B { virtual void f(); };
struct C { virtual void f() final; };
void a(A& a) { a.f(); }
void b(B& b) { b.f(); }
void c(C& c) { c.f(); }

like this

g++ call.cpp -std=c++11 -O3 -S -o- -masm=intel # gcc-4.7.2 i686-pc-cygwin

which produced [output that included] this

__Z1aR1A:
    jmp __ZN1A1fEv

__Z1bR1B:
    mov eax, DWORD PTR [esp+4]
    mov edx, DWORD PTR [eax]
    mov eax, DWORD PTR [edx]
    jmp eax

__Z1cR1C:
    jmp __ZN1C1fEv

What does it mean? Because C::f() is marked final, calls to it can be devirtualized by the compiler, so there is no extra indirection when calling it in the above case.

(Trying the same code with VS2012’s cl.exe, the call to C::f() does not appear to be devirtualized)

struct C does still appear to have a virtual function table pointer: (sizeof(C) == sizeof(B) == 4), whereas (sizeof(A) == 1)It seems to me that the vtable pointer could be omitted in this case…

Update (2015-01-24): As Tom points out below, anyone with a B* or B& that is actually pointing to an object of type C will still require the vtable pointer to find the correct implementation of f().

2 thoughts on “Can C++11’s final qualifier affect codegen?”

  1. I don’t think you can actually get rid of the vtable. That would have to happen during compilation, not linking, but there might be some other place in your program that uses that vtable, that represents a C as a reference or pointer to B. (And other things, like dynamic_cast, might also use that vtable without actually calling anything from it.)

Leave a Reply

Your email address will not be published.