clang:没有超出虚拟方法的定义(纯粹的抽象C ++类) [英] clang: no out-of-line virtual method definitions (pure abstract C++ class)

查看:2229
本文介绍了clang:没有超出虚拟方法的定义(纯粹的抽象C ++类)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图使用Clang-3.5编译以下简单的C ++代码:



test.h:

  class A 
{
public:
A();
virtual〜A()= 0;
};

test.cc:

  #includetest.h

A :: A(){;}
A ::〜A(){;}

用于编译此命令(Linux,uname -r:3.16.0-4-amd64) p>

  $ clang-3.5 -Weverything -std = c ++ 11 -c test.cc 



我得到的错误:

  ./test.h:1:7:warning:'A'没有超出虚拟方法的定义;其vtable将在每个翻译单元中发出[-Wweak-vtables] 

任何提示为什么这是发射一个警告?虚拟析构函数根本不内联。恰恰相反,在test.cc.中提供了一个超出行的定义。



我不认为这个问题是重复的:
什么意思clang的-Wweak-vtables?
as FilipRoséen建议。在我的问题中,我具体指的是纯抽象类(在建议的副本中没有提到)。我知道 -Wweak-vtables 如何工作与非抽象类,我很好。在我的例子中,我在实现文件中定义析构函数(它是纯抽象的)。这应该防止Clang发出任何错误,即使使用 -Wweak-vtables

解决方案

暂时,让我们忘记纯虚函数,并试着理解编译器如何避免在包含多态类声明的所有翻译单元中发出vtable。



当编译器看到具有虚函数的类的声明时,它检查是否有在类声明中声明但没有定义的虚函数。如果只有一个这样的函数,则编译器肯定知道它必须被定义在某处(否则程序将不链接),并且仅在主管该函数的定义的翻译单元中发出vtable 。如果有多个这样的函数,编译器使用一些确定性选择标准选择其中之一,并且关于在何处发出vtable的决定 - 忽略其他选择标准。选择这样的单个代表性虚拟函数的最简单的方法是从候选集合中取第一个,这是俚语。



因此,优化是选择一个虚拟方法,以便编译器可以保证在一些翻译单元中会遇到该方法的(单一)定义。



现在,类声明包含纯虚函数?程序员可以提供纯虚拟功能的实现,但不必!因此,纯虚拟函数不属于候选虚拟方法的列表,编译器可从中选择代表性虚拟方法。



但是有一个异常 - 纯虚拟析构函数!



纯虚拟析构函数是一种特殊情况:


  1. 如果您不想从中抽取其他类,抽象类就没有意义。

  2. 一个子类的析构函数总是调用基类的析构函数。

  3. 从具有虚拟析构函数的类派生的类的析构函数自动是一个虚函数。

  4. 程序创建对象的所有类的所有虚拟函数通常被链接到最终的可执行文件(包括可以被静态证明保持未使用的虚拟函数,

  5. 因此,纯虚拟析构器必须具有用户提供的定义。

因此,clang在问题示例中的警告在概念上是不合理的。



但是,从实际的角度该示例的重要性是最小的,因为纯虚拟析构器很少(如果有的话)需要。我不能想象一个或多或少的现实情况下,纯虚拟析构函数不会伴随另一个纯虚函数。但是在这样的设置中,(虚拟)析构函数的纯净性的需求完全消失,因为类由于存在其他纯虚方法而变得抽象。


I'm trying to compile the following simple C++ code using Clang-3.5:

test.h:

class A
{
  public:
    A();
    virtual ~A() = 0;
};

test.cc:

#include "test.h"

A::A() {;}
A::~A() {;}

The command that I use for compiling this (Linux, uname -r: 3.16.0-4-amd64):

$clang-3.5 -Weverything -std=c++11 -c test.cc

And the error that I get:

./test.h:1:7: warning: 'A' has no out-of-line virtual method definitions; its vtable will be emitted in every translation unit [-Wweak-vtables]

Any hints why this is emitting a warning? The virtual destructor is not inlined at all. Quite the opposite, there's a out-of-line definition provided in test.cc. What am I missing here?

Edit

I don't think that this question is a duplicate of : What is the meaning of clang's -Wweak-vtables? as Filip Roséen suggested. In my question I specifically refer to pure abstract classes (not mentioned in the suggested duplicate). I know how -Wweak-vtables works with non-abstract classes and I'm fine with it. In my example I define the destructor (which is pure abstract) in the implementation file. This should prevent Clang from emitting any errors, even with -Wweak-vtables.

解决方案

For a moment, let's forget about pure virtual functions and try to understand how the compiler can avoid emitting the vtable in all translation units that include the declaration of a polymorphic class.

When the compiler sees the declaration of a class with virtual functions, it checks whether there are virtual functions that are only declared but not defined inside the class declaration. If there is exactly one such function, the compiler knows for sure that it must be defined somewhere (otherwise the program will not link), and emits the vtable only in the translation unit hosting the definition of that function. If there are multiple such functions, the compiler choses one of them using some deterministic selection criteria and - with regard to the decision of where to emit the vtable - ignores the other ones. The simplest way to select such a single representative virtual function is to take the first one from the candidate set, and this is what clang does.

So, the key to this optimization is to select a virtual method such that the compiler can guarantee that it will encounter a (single) definition of that method in some translation unit.

Now, what if the class declaration contains pure virtual functions? A programmer can provide an implementation for a pure virtual function but (s)he is not obliged to! Therefore pure virtual functions do not belong to the list of candidate virtual methods from which the compiler can select the representative one.

But there is one exception - a pure virtual destructor!

A pure virtual destructor is a special case:

  1. An abstract class doesn't make sense if you are not going to derive other classes from it.
  2. A subclass' destructor always calls the base class' destructor.
  3. The destructor of a class deriving from a class with a virtual destructor is automatically a virtual function.
  4. All virtual functions of all classes, that the program creates objects of, are usually linked into the final executable (including the virtual functions that can be statically proved to remain unused, though that would require static analysis of the full program).
  5. Therefore a pure virtual destructor must have a user-provided definition.

Thus, clang's warning in the question's example is not conceptually justified.

However, from the practical point of view the importance of that example is minimal, since a pure virtual destructor is rarely, if at all, needed. I can't imagine a more or less realistic case where a pure virtual destructor won't be accompanied by another pure virtual function. But in such a setup the need for the pureness of the (virtual) destructor completely disappears, since the class becomes abstract due to the presence of other pure virtual methods.

这篇关于clang:没有超出虚拟方法的定义(纯粹的抽象C ++类)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆