“vtable”链接器错误(涉及带有“=default”的虚拟析构函数)- Clang 3.1 中的潜在错误?

Posted

技术标签:

【中文标题】“vtable”链接器错误(涉及带有“=default”的虚拟析构函数)- Clang 3.1 中的潜在错误?【英文标题】:"vtable" linker error (involving a virtual destructor with "=default") - potential bug in Clang 3.1? 【发布时间】:2012-12-15 10:43:12 【问题描述】:

我的代码中出现链接器错误。我已将其归结为以下基本要素。

这段代码给出了链接器错误“vtable for Foo”,引用自:Foo::Foo()

class Foo 
public:
  Foo();
  virtual ~Foo() = default;
;
Foo::Foo()  

但是这段代码没有给出任何错误:

class Foo 
public:
  Foo();
  virtual ~Foo()  
;
Foo::Foo()  

为什么?我认为= default 应该与那些空方括号基本上做同样的事情。

更新:我正在使用“Apple LLVM 编译器 4.1”,它是 Xcode 4.5.2 的一部分。这可能是这个编译器中的一个错误吗?它可能适用于最新的 GCC(尽管 Apple 不再发布)。有关编译器的讨论,请参见下面的 cmets。

更新 2: 如下所述,将行更改为 virtual inline ~Foo() = default; 可以消除此错误。这难道不是必须成为一个错误吗?在这种情况下,如果没有明确写出inline,编译器似乎无法识别内联函数。

【问题讨论】:

试试virtual ~Foo() noexcept = default;。我想我曾经遇到过类似的问题并放弃了default。此外,我认为甚至还有一个 DR。 @KerrekSB 链接器错误仍然存​​在noexcept 这适用于我的 gcc 4.7.2。 @Kocka 嗯。我正在运行“Apple LLVM Compiler 4.1”,作为 Xcode 4.5.2 的一部分。所以也许这只是一个编译器错误:( 它也适用于 clang 3.1。 【参考方案1】:

It appears to be a bug in clang which has been fixed already.您问得恰到好处,因为很快就会有新版本发布:release candidates are already available。请试一试,您的示例适用于 i386-linux 二进制版本,并且应该适用于所有这些版本。

【讨论】:

哦,亲爱的!我将等待真正的 Clang 3.2 出现在 Xcode 中。大概需要几个月的时间。在那之前,我会把额外的“内联”留在那里。 很好地发现了这一点!我喜欢两行代码的修复方式;)【参考方案2】:

在 Itanium ABI 中,为包含未在类中内联定义的第一个虚拟方法的定义的翻译单元发出 v-table(和其他 RTTI 信息),或者如果只有内联定义的虚拟方法,则包含该类的每个翻译单元。然后由链接器来合并冗余符号。

有可能通过指定 = default,Clang 没有意识到您在类中定义virtual 方法,并且包含您的文件的每个 TU 都应该定义v-table 和 RTTI 信息,而是等待定义出现在某处。

我可以建议将定义放在类之外吗? => Foo::~Foo() = default;

【讨论】:

Foo::~Foo() = default; 放入实现文件(即不是类定义所在的头文件)确实有效。然而,有趣的是,它还可以将inline 添加到类本身的行中:virtual inline ~Foo() = default; 这不是一个保证的错误吗?似乎它无法识别内联,即使它是内联的。 @DennisRitchie:这听起来确实像一个错误。我并不感到惊讶,因为= default 是一个新结构。像所有新东西一样,清除错误需要时间。 我刚刚发现,如果只存在从Foo 派生的子类(即使子类为空),链接器错误就会消失。你有什么技术解释为什么这会让编译器更快乐? @DennisRitchie: no :x bug 的问题是它们很脆弱。【参考方案3】:

它适用于 g++ 4.7.2。但是我和你在 clang 3.1 有同样的问题。

我有 3 个文件。

Foo.h:

#ifndef FOO_H
#define FOO_H

class Foo 
public:
  Foo();
  virtual ~Foo() = default;
;

#endif // FOO_H

Foo.cpp:

#include "Foo.h"

Foo::Foo()  

main.cpp:

#include <iostream>
#include "Foo.h"

using namespace std;

int main()

    Foo foo;
    return 0;

但如果是这样,它也适用于 clang:

Foo.cpp 为空。

main.cpp

#include <iostream>
#include "Foo.h"

using namespace std;

Foo::Foo()  

int main()

    Foo foo;
    return 0;

所以我猜clang在生成目标文件时有错误。

【讨论】:

以上是关于“vtable”链接器错误(涉及带有“=default”的虚拟析构函数)- Clang 3.1 中的潜在错误?的主要内容,如果未能解决你的问题,请参考以下文章

为啥即使不涉及虚函数,虚继承也需要vtable?

使用 Qt 对 vtable 的未定义引用

带有模板类的 Windows DLL 链接器错误

带有 -mavx 标志的链接器错误 GCC7

iOS中的vtable错误

使用带有 fftw3 Visual Studio 2010 的 openCV 的链接器错误