13

私のライブラリには、基本クラスと派生クラスの 2 つのクラスがあります。ライブラリの現在のバージョンでは、基本クラスに仮想関数 foo() があり、派生クラスはそれをオーバーライドしません。次のバージョンでは、派生クラスでオーバーライドしたいと考えています。これはABIを壊しますか?通常、新しい仮想関数を導入することで問題が解決することはわかっていますが、これは特殊なケースのようです。私の直感では、テーブルのサイズを実際に変更することなく、vtbl のオフセットを変更する必要があります。

明らかに、C++ 標準は特定の ABI を義務付けていないため、この質問はプラットフォーム固有のものですが、実際には、ABI を壊して維持するものはほとんどのコンパイラで似ています。私はGCCの振る舞いに興味がありますが、人々がより多くのコンパイラに答えることができれば、この質問はより有用になります;)

4

5 に答える 5

11

かもしれない。

あなたはオフセットに関して間違っています。vtable のオフセットは既に決定されています。何が起こるかというと、Derived クラス コンストラクターは、そのオフセットにある関数ポインターを Derived オーバーライドに置き換えます (クラス内の v ポインターを新しい v テーブルに切り替えることによって)。したがって、通常は ABI 互換です。

ただし、最適化、特に関数呼び出しの非仮想化のために、問題が発生する可能性があります。

通常、仮想関数を呼び出すと、コンパイラは vpointer を介して vtable にルックアップを導入します。ただし、オブジェクトの正確なタイプを (静的に) 推測できる場合は、呼び出す正確な関数を推測して、仮想ルックアップを削減することもできます。

例:

struct Base {
  virtual void foo();
  virtual void bar();
};

struct Derived: Base {
  virtual void foo();
};

int main(int argc, char* argv[]) {
  Derived d;
  d.foo(); // It is necessarily Derived::foo
  d.bar(); // It is necessarily Base::bar
}

そしてこの場合...単に新しいライブラリとリンクするだけでは、Derived::bar.

于 2011-04-21T15:21:46.530 に答える
7

これは、一般的に特に信頼できるもののようには思えません-あなたが言ったように、C++ ABIはかなりトリッキーです(コンパイラオプションに至るまで)。

そうは言ってもg++ -fdump-class-hierarchy、変更を加える前後に使用して、親または子の vtables の構造が変化するかどうかを確認できると思います。そうでない場合は、ABI を壊していないと仮定するのがおそらく「かなり」安全です。

于 2011-04-21T15:20:09.807 に答える
1

私の直感では、テーブルのサイズを実際に変更することなく、vtbl のオフセットを変更する必要があります。

さて、あなたの直感は明らかに間違っています。

  • vtable にオーバーライド用の新しいエントリがあるか、後続のすべてのエントリが移動され、テーブルが大きくなります。
  • または、新しいエントリがなく、vtable 表現が変更されません。

どちらが正しいかは、多くの要因によって異なります。

とにかく:それを当てにしないでください。

于 2012-08-07T22:30:52.157 に答える
0

注意: C++ では、既存の仮想関数をオーバーライドすると ABI が壊れますか?を参照してください。このロジックが当てはまらない場合。

私の考えでは、 g++ -fdump-class-hierarchy を使用するというマークの提案は、適切な回帰テストを行った直後に、ここで勝者になるでしょう


オーバーライドしても、 vtable レイアウトは変更されません[1]。vtable エントリ自体は、ライブラリ、IMHO のデータ セグメントにあるため、変更しも問題は発生しません。

もちろん、アプリケーションを再リンクする必要があります。そうしないと、消費者が &Derived::overriddenMethod; への直接参照を使用していた場合に破損する可能性があります。コンパイラがそれを &Base::overriddenMethod に解決することが許可されていたかどうかはわかりませんが、申し訳ありませんが安全です。

[1] 説明: これは、メソッドがそもそも仮想であったことを前提としています!

于 2011-04-21T15:25:20.540 に答える