“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 中的潜在错误?的主要内容,如果未能解决你的问题,请参考以下文章