5

While there are other questions on stack overflow which deal with the 'undefined reference to vtable' error message. The following code either compiles or doesn't compile depending on whether the no-args constructor C() is implemented in-line or not. I know that the member function m() should be pure virtual and that would be the correct change to make in order to fix the issue. What is confusing to me is that it can be made to compile with an apparently unrelated change.

The following code does not compile with g++ (4.6.3 on ubuntu 64 bit) and produces the expected 'undefined reference to vtable for C' message (which for the record is still a terrible error message considering the problem is with m())

Header.h

#ifndef HEADER_H
#define HEADER_H

class C
{
  public:
    C();
    virtual void m();
};

#endif

Implementation.cpp

#include "Header.h"
C::C() {}

Main.cpp

#include "Header.h"
int main()
{
   return 0;
}

The following unrelated changes allows for compilation:

  • Remove non in-lined implementation for C::C() from Implementation.cpp
  • Add trivial in-line implementation for C() to class in Header.h

Why does this allow for compilation? Is this a compiler bug, optimizer issue or dark corner of the standard suprise?

1 Answer 1

7

Is this a compiler bug, optimizer issue or dark corner of the standard suprise?

None of the above. It's not a bug, it's nothing to do with optimisation, and this particular issue is outside the scope of the standard, it's covered by the relevant ABI (which is only a de facto standard.)

C::m is the key function and you haven't defined it anywhere, which means the compiler doesn't emit the vtable.

There are good (if complicated) reasons why the code compiles with those changes:

  • Remove non in-lined implementation for C::C() from Implementation.cpp

For some complicated reasons described in 2.6 in the ABI document, vtables are needed during construction. So the definition of the constructor creates a reference to the vtable, which the linker tells you is missing at link-time. If you remove the definition of the constructor then there's no reference to the vtable.

  • Add trivial in-line implementation for C() to class in Header.h

An inline function that isn't called in a given translation unit will not be emitted in the object file, so making the function inline means the constructor isn't in the object file, so the object file doesn't refer to the vtable, and the linker doesn't need to look for it at link-time.

If you change the program so the inline constructor is actually used (e.g. by creating a C in main) then you'll get the same linker error back again, because now the inline constructor will be defined in Main.o and so the vtable is needed.

class C
{
  public:
    C() { }  // inline
    virtual void m();
};

int main()
{
    C c;
}
Sign up to request clarification or add additional context in comments.

5 Comments

+1, although the complicated reasons why the vtable is required during construction is quite simple: the compiler must set the vptr to point to it :)
Yes, the ABI makes it sound very complicated, but that's it! :)
I actually did some hand-waving there. In this particular case it is as simple as that, but the ABI must deal with all cases which makes it more complicated. Consider, for example, creation of a derived type. While it might not seem obvious at first, the vtable of the base is required even if no object of type base is ever created.
I couldn't really hope for a more comprehensive answer. So its more of a pseudo-standards surprise then.
Ah, thanks so much - this was my issue. All my functions were inlined on my base class, so there was no vtable!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.