Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Undefined reference to vtable error affected by inline constructor

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?

like image 334
DuncanACoulter Avatar asked Aug 23 '12 12:08

DuncanACoulter


People also ask

How do you fix a undefined reference in C++?

When we compile these files separately, the first file gives “undefined reference” for the print function, while the second file gives “undefined reference” for the main function. The way to resolve this error is to compile both the files simultaneously (For example, by using g++).

How do you fix undefined references to Main?

To fix this error, correct the spelling of the main() function.

What is undefined reference?

The Undefined reference is one of those exceptions that occurred mostly in the C language, as the name suggests that it would occur when some function definition is missing from the script.


1 Answers

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;
}
like image 122
Jonathan Wakely Avatar answered Oct 19 '22 23:10

Jonathan Wakely