web-dev-qa-db-ja.com

金で説明されているC ++の「キー機能」とは何ですか?

「このエラーメッセージを解決するにはどうすればよいですか?」という質問には答えないでください。

ゴールドが提供するエラーメッセージ:

/usr/bin/ld.gold: the vtable symbol may be undefined
because the class is missing its key function

key functionとは何ですか? dllimportセクションの下の 関数属性のGCCマニュアルページ に参照があります。関連するテキストは次のとおりです。

SH Symbian OSターゲットでは、dllimport属性にも別の影響(sic)があります。これにより、クラスのvtableおよび実行時の型情報がエクスポートされる可能性があります。これは、クラスにdllimport'edコンストラクターまたは非インライン、非純粋仮想関数があり、これら2つの条件のいずれかに対して、クラスにインラインコンストラクターまたはデストラクタがあり、キー関数が現在の翻訳単位。

このことから、Symbian OSでdllimport属性を使用する場合、特定の条件下で必要となる、コンストラクターまたはデストラクタとは異なる関数があることを取り上げます。おもしろいですが、Linux上でLinux向けにコンパイルしていますが、grep -r dllimportは何も明らかにしません。したがって、この段落は適用されません。

(FWIW問題は(この例では)未定義destructorから派生しますが、ドキュメントとリンカーの出力の両方が、 "他の種類の欠落シンボルについては、リンカは欠落シンボルの名前を綴ります。)

では、key functionreallyとは何ですか?

29
Cuadue

キー関数は、クラスで宣言された最初の非インライン仮想関数として定義されます。それについての公式gcc wikiは here です。

25
navylover

(コメントからの移動/拡張)

@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;
}

[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

これを通常の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

わかった、だから何? vtableを明示的に定義しなければならないというわけではないので、この種のエラーを修正するためにどこから調べ始めるべきかは明らかではありません。


  1. ただし、このような関数は、ベースクラスへのポインタを介して間接で呼び出すことができます。リンカーは、この関数の唯一の参照として、関数ではなくvtableへの未定義の参照のみを表示します。ケースはvtableにありますが、これはありません。
15
Matteo Italia