什么是黄金描述的C++"关键功能"?

Cua*_*due 31 c++ gcc ld

请不要回答"如何解决此错误消息?"的问题.

在gold提供的错误消息中:

/usr/bin/ld.gold: the vtable symbol may be undefined
because the class is missing its key function
Run Code Online (Sandbox Code Playgroud)

什么是key function?我在该部分下的功能属性GCC手册页中找到了对它的引用dllimport.相关文字如下:

在SH Symbian OS目标上,dllimport属性还有另一种影响(原文如此) - 它可以导致类的vtable和运行时类型信息被导出.当类具有dllimport'ed构造函数或非内联非纯虚函数时会发生这种情况,并且对于这两个条件中的任何一个,该类还具有内联构造函数或析构函数,并且具有在现翻译单位.

从中我可以看出,在某些条件下dllimport,在Symbian OS上使用属性时,有一些与构造函数或析构函数不同的函数.有意思,但我正在为Linux上的Linux编译,并且grep -r dllimport什么也没透露.所以这一段不适用.

(FWIW问题来自(在这种情况下)来自未定义的析构函数,但是文档和链接器的输出都非常痛苦地区分"关键函数"和析构函数.对于其他类型的缺失符号,链接器拼写缺少符号的名称.)

那么,key function 真的什么

nav*_*ver 26

key函数定义为类中声明的第一个非内联虚函数.关于它的官方gcc wiki就在这里.

  • @MikeMB:通过上面的链接:“只要有可能,vtable只会在单个目标文件中生成和输出,而不是在引用该类的每个目标文件中生成vtable(可能是数百个包含标头的对象,但是实际上不使用该类。)”。我怀疑您的情况属于上述“在任何可能的情况下”,因此将在每个TU中生成一个具有与“内联”函数相同属性的vtable,并且链接程序将知道它可以随机选择一个。我将做一些测试,看看是否是这种情况。 (3认同)
  • 如果所有虚拟函数都内联定义会怎样? (2认同)

Mat*_*lia 17

(从评论中移动/扩展)

正如@navylover所解释的那样,关键函数是类中定义的第一个非内联虚函数; 这很重要,因为它被编译器用作传统标记来决定必须发出什么样的TU(因为它必须只发射一次) - 无论哪个TU包含关键函数的定义,相应的对象模块都将包含vtable也是如此.

因此,如果没有TU定义键函数(例如,因为你忘了定义它),vtable将永远不会被发出,因此错误.

黄金试图暗示你正确的方向:如果vtable丢失,可能是因为关键功能也缺失(再次,因为你没有定义或忘记链接其模块),虽然它可能不会显式列为未定义的引用(可能会使您走上正确的轨道),因为在其余代码中没有人直接调用它1,如下例所示:

struct Test {
    virtual void foo();
    virtual int bar() {
        return 0;
    }
};

int main() {
    Test t;
    t.bar();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

 

[matteo@teolapkubuntu /tmp]$ g++ -fuse-ld=gold keyf.cpp 
/tmp/ccduMsT3.o:keyf.cpp:function main: error: undefined reference to 'vtable for Test'
/usr/bin/ld.gold: the vtable symbol may be undefined because the class is missing its key function
Run Code Online (Sandbox Code Playgroud)

将其与常规GNU ld进行比较,后者只是说

[matteo@teolapkubuntu /tmp]$ g++ keyf.cpp 
/tmp/ccUr3Xyi.o: In function `main':
keyf.cpp:(.text+0x1a): undefined reference to `vtable for Test'
collect2: error: ld returned 1 exit status
Run Code Online (Sandbox Code Playgroud)

好的,那又怎样?这不像我必须明确定义vtables,所以我应该从哪里开始寻找修复这种错误的绝对不明显.


  1. 但是,这样的函数可以通过指向基类的指针间接调用,并且链接器仍然只显示对vtable的未定义引用而不是函数,因为在这种情况下对函数的唯一引用将在vtable中,缺少了.