clang: no out-of-line virtual method definitions (pure abstract C++ class)
We don't want to place the vtable in each translation unit. So there must be some ordering of translation units, such that we can say then, that we place the vtable in the "first" translation unit. If this ordering is undefined, we emit the warning.
You find the answer in the Itanium CXX ABI. In the section about virtual tables (5.2.3) you find:
The virtual table for a class is emitted in the same object containing the definition of its key function, i.e. the first non-pure virtual function that is not inline at the point of class definition. If there is no key function, it is emitted everywhere used. The emitted virtual table includes the full virtual table group for the class, any new construction virtual tables required for subobjects, and the VTT for the class. They are emitted in a COMDAT group, with the virtual table mangled name as the identifying symbol. Note that if the key function is not declared inline in the class definition, but its definition later is always declared inline, it will be emitted in every object containing the definition.
NOTE: In the abstract, a pure virtual destructor could be used as the key function, as it must be defined even though it is pure. However, the ABI committee did not realize this fact until after the specification of key function was complete; therefore a pure virtual destructor cannot be the key function.
The second section is the answer to your question. A pure virtual destructor is no key function. Therefore, it is unclear where to place the vtable and it is placed everywhere. As a consequence we get the warning.
You will even find this explanation in the Clang source documentation.
So specifically to the warning: You will get the warning when all of your virtual functions belong to one of the following categories:
inline
is specified forA::x()
in the class definition.struct A {
inline virtual void x();
virtual ~A() {
}
};
void A::x() {
}B::x() is inline in the class definition.
struct B {
virtual void x() {
}
virtual ~B() {
}
};C::x() is pure virtual
struct C {
virtual void x() = 0;
virtual ~C() {
}
};(Belongs to 3.) You have a pure virtual destructor
struct D {
virtual ~D() = 0;
};
D::~D() {
}In this case, the ordering could be defined, because the destructor must be defined, nevertheless, by definition, there is still no "first" translation unit.
For all other cases, the key function is the first virtual function that does not fit to one of these categories, and the vtable will be placed in the translation unit where the key function is defined.
Declaring an interface in C++ and not emmiting its vtable to every translation unit
You already have a non-pure virtual function: the destructor! Just define it in its own translation unit.
// IDemo.h
class IDemo
{
public:
virtual ~IDemo();
virtual void OverrideMe() = 0;
};
// IDemo.cpp
IDemo::~IDemo() = default;
What is the meaning of clang's -Wweak-vtables?
If all of a class's virtual
methods are inline, the compiler has no way to select a translation unit in which to place a single shared copy of the vtable — instead, a copy of the vtable has to be placed in each object file that needs it. On many platforms the linker is able to unify these multiple copies, either by discarding duplicate definitions or by mapping all references to one copy, so this is only a warning.
Implementing a virtual
function out-of-line enables the compiler to select the translation unit that implements that out-of-line method as a "home" for the class's implementation details, and places the single shared copy of the vtable in the same translation unit. If multiple methods are out-of-line, an arbitrary choice of method may be made by the compiler so long as that choice is determined only by the class's declaration; for example, GCC chooses the first non-inline method in declaration order.
If you don't override any method of a class, the virtual
keyword has no observable effect, so there's no need for the compiler to emit a vtable for the class. If you do not derive from A
, or if you fail to declare a derived class's destructor virtual
, there are no overridden methods in A
and thus A
's vtable is omitted. If you declare an additional out-of-line virtual
method to suppress the warning and also do something that overrides a method in A
, the implementation of the non-inline virtual
(and its accompanying copy of the vtable) needs to be supplied in a linked translation unit, otherwise linking will fail because the vtable is missing.
Declaring abstract class (pure virtual method) increase binary size substantially
It's almost certainly because of unexpected inclusion of exception handling, which libc++ has built into it, regardless of whether or not you compile your code with --noexception
or whatever the proper gnu-ism is.
The exception in question is probably 'pure virtual function call' or something like that (a fairly obscure runtime error to get, but possible if you call virtual functions in the base class constructor).
The answer is to provide your own empty implementation of this, atexit(), and whatever random callout that you don't really need. Once you do that, the linker won't drag in the other stuff (which drags in other stuff, which drags in other stuff, etc).
void __cxa_pure_virtual(void)
{
BKPT();
}
Is what I have on our project, though things may have changed in your version of libc++
Virtual destructor for pure abstract base classes
Whereas, clang generates warning for:
class A {
public:
virtual ~A() {}
virtual void foo() = 0;
};
using = default
doesn't trigger it.
class A {
public:
virtual ~A() = default;
virtual void foo() = 0;
};
Even if both are valid.
Demo
Determine if a member call is virtual in the Clang AST
The distinguishing factor is hasQualifier
on the MemberExpr
of the callee object. If hasQualifier
is true
, then the function call is non-virtual
.
Avoid weak-vtable warnings for classes only defined in a source file
It turns out that standalone clang does the right thing by default, only the clang code model in Qt creator shows the useless warning. It's already reported as QTCREATORBUG-19741, so there's nothing more to do than wait for an updated Qt creator version.
Related Topics
Explicit Return Type of Lambda
How to Enable_Shared_From_This of Both Parent and Derived
Best Library for Statistics in C++
When Is a Vtable Created in C++
What Is the Safe Way to Fill Multidimensional Array Using Std::Fill
Why Don't Std::Vector's Elements Need a Default Constructor
Returning Non-Const Reference from a Const Member Function
Incrementing Iterators: Is ++It More Efficient Than It++
Was Not Declared in This Scope' Error
Calling a Function Through Its Address in Memory in C/C++
How to Block Running Two Instances of the Same Program
Access Private Member Using Template Trick
C++ [Windows] Path to the Folder Where the Executable Is Located