【问题标题】:Undefined reference to vtable error affected by inline constructor受内联构造函数影响的对 vtable 错误的未定义引用
【发布时间】:2012-08-18 23:31:09
【问题描述】:

虽然还有其他关于堆栈溢出的问题涉及“未定义对 vtable 的引用”错误消息。以下代码编译或不编译取决于无参数构造函数 C() 是否内联实现。我知道成员函数 m() 应该是纯虚拟的,这将是解决问题的正确更改。令我困惑的是,它可以通过明显不相关的更改进行编译。

以下代码不能使用 g++(ubuntu 64 位上的 4.6.3)编译,并产生预期的“未定义对 C 的 vtable 的引用”消息(考虑到问题出在 m 上,这仍然是一个可怕的错误消息())

头文件.h

#ifndef HEADER_H
#define HEADER_H

class C
{
  public:
    C();
    virtual void m();
};

#endif

实施.cpp

#include "Header.h"
C::C() {}

Main.cpp

#include "Header.h"
int main()
{
   return 0;
}

以下不相关的更改允许编译:

  • 从 Implementation.cpp 中删除 C::C() 的非内联实现
  • 将 C() 的简单内联实现添加到 Header.h 中的类

为什么这允许编译?这是编译器错误、优化器问题还是标准惊喜的暗角?

【问题讨论】:

    标签: c++ constructor compiler-errors g++ vtable


    【解决方案1】:

    这是编译器错误、优化器问题还是标准惊喜的暗角?

    以上都不是。这不是错误,与优化无关,而且这个特定问题超出了标准的范围,相关的ABI 涵盖了它(这只是一个事实上的标准。)

    C::mkey function 并且您没有在任何地方定义它,这意味着编译器不会发出 vtable。

    使用这些更改编译代码有很好的(如果复杂的话)原因:

    • 从 Implementation.cpp 中删除 C::C() 的非内联实现

    由于ABI文档中2.6中描述的一些复杂原因,在构建过程中需要vtables。因此,构造函数的定义创建了对 vtable 的引用,链接器会告诉您在链接时缺少该引用。如果您删除构造函数的定义,则没有对 vtable 的引用。

    • 将 C() 的简单内联实现添加到 Header.h 中的类

    在给定翻译单元中未调用的内联函数不会在目标文件中发出,因此使函数内联意味着构造函数不在目标文件中,因此目标文件不引用vtable,链接器不需要在链接时查找它。

    如果您更改程序以便实际使用内联构造函数(例如,通过在main 中创建C),那么您将再次得到相同的链接器错误,因为现在内联构造函数将在@ 中定义987654327@,所以需要vtable。

    class C
    {
      public:
        C() { }  // inline
        virtual void m();
    };
    
    int main()
    {
        C c;
    }
    

    【讨论】:

    • +1,虽然复杂的原因为什么在构造过程中需要 vtable 非常简单:编译器必须设置 vptr 指向它:)
    • 是的,ABI 让它听起来很复杂,但就是这样! :)
    • 我确实在那里挥手过。在这种特殊情况下,它就这么简单,但是 ABI 必须处理所有情况,这使得它变得更加复杂。例如,考虑创建派生类型。虽然一开始可能看起来并不明显,但即使没有创建 base 类型的对象,也需要 base 的 vtable。
    • 我真的不希望得到更全面的答案。所以这更像是一个伪标准的惊喜。
    • 啊,非常感谢 - 这是我的问题。我所有的函数都内联在我的基类中,所以没有 vtable!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-08
    • 2020-07-07
    • 2015-05-25
    • 2014-06-05
    • 1970-01-01
    相关资源
    最近更新 更多