VIDTAKER.COM

Q&A

C + +でインターフェイスを操作するためのパフォーマンスペナルティ?


そこにランタイムパフォーマンスの低下は、C + +でインターフェイス(抽象基本クラス)を使用していますか?



19 Replies

1)

回答ショート:いいえ

ロング回答:これは、高速化がされていない基本に影響を与えるか、クラス数階層のあるののクラスは祖先。唯一のメソッド呼び出しのコストです。

非仮想メソッドの呼び出しは、コストを(てインラインすることができます)
単純なテーブルを見る)を検索しませんです、これはしかし、(それはメソッド呼び出しが呼び出しあなたがいるコストを少し高いように前に必要に見る呼び出すメソッドを仮想。インターフェイス上のすべてのメソッドから仮想定義が、このコストがそうです。

これは問題にはならないいくつかの超高速に敏感なアプリケーション記述している場合を除き。余分な明瞭では、インターフェイスを使用してから表示されます通常任意の知覚速度の低下を補います。


2)

また、仮想関数あたり小さなペナルティは通常の通話に比べて呼んでいます。あなたは1秒あたりの呼び出し数千数百人をやっている場合を除き、違いを観察するそうであり、価格は頻繁に追加されたコードの明確化のため支払う価値がとにかくです。


3)

C + +で仮想関数テーブルを使用して一般的に任務を抽象基本クラスを使用して、すべてのインターフェイスの呼び出しは、そのテーブルをルックアップする予定です。コストは原料の関数呼び出しに、そうすることが必要必ず速いことよりも心配する前に行くことに比べて小さいです。


4)

唯一の主な違いは私が知っているので、あなたは、インライン具象クラスを使用していないです(くらいですか?)行うには困難です。


5)

ができると思います私は事は遅くに電話をより非している呼び出しが仮想メソッドため、行くビットであることはほとんどされるメソッドは、仮想仮想メソッドテーブル

しかし、これは悪い理由あなたのデザインを台無しにすることです。あなたは、より高速なサーバーを使用するより高い性能が必要な場合。


6)

場合は仮想関数を(インターフェイスを介し言う)プログラムを呼び出すまで関数のテーブル内のどの関数がそのオブジェクトの呼び出しを確認することない。これは小さなペナルティ関数を直接呼び出すと比較して提供します。

また、ときにコンパイラが関数呼び出しをインラインすることはできません仮想関数を使用します。いくつかの小さな関数の仮想関数を使用して、したがって、そこにペナルティことができます。これは一般的に最大のパフォーマンス"ヒット"あなたが見たいと予想される。これは本当に唯一の問題は関数が小さく、いわゆる何度もされた場合、ループ内からと言う。


7)

仮想関数を含む任意のクラスについては、vtableは使用されます。明らかに、vtableのように派遣機構を介してメソッドを呼び出す直接呼び出しよりも遅いですが、ほとんどの場合は、一緒に暮らすことができます。


8)

はい、何も私の知識に注目。パフォーマンスヒットは、各メソッドの呼び出しを持っている'間接'のためだ。

しかし、実際にいくつかのコンパイラは、メソッドをインライン化することはできませんので、あなたが使用しているコンパイラに依存するクラスの抽象基本クラスから継承内で呼び出し。

あなたがあなた自身のテストを実行する必要がありますことを確認する場合。




9)

答えは、この問題関連しても。


10)

注意しなければならないことの一つは、仮想関数呼び出しのコスト別の1つのプラットフォームごとに異なることができます。で、彼らがより顕著として通常vtableの呼び出しは、キャッシュは、ミス分岐予測を台無しにできることを意味する可能性がありますコンソール。


11)

仮想呼び出しは、インラインされていません

そこを忘れては簡単です仮想関数のペナルティの一種:仮想呼び出しはインライン化されないことです。関数が小さく、適切なインラインの場合は、このペナルティが非常に重要な、あなただけでなく、呼び出しのオーバーヘッドを追加する、それが仮想関数を想定している呼び出し元の関数(最適化する方法コンパイラでも限られているものではありませんが可能性がありますいくつかのレジスタやメモリの場所を変更して、それが)呼び出し元と呼び出しの間の定数値を伝播することはできません。

仮想通話料金は、プラットフォームに依存する

通常の関数呼び出しに比べて呼び出しのオーバーヘッドのペナルティとして、答えはあなたのターゲットプラットフォームに依存します。あなたのx86/x64のCPUは、仮想関数を呼び出すためのペナルティを搭載したPCをターゲットにしている場合非常に小さく、現代のx86/x64のようにCPUは、間接呼び出しで分岐予測を行うことができます。他のRISC(プラットフォームプラットフォームいくつかの可能性がありますがかなり高いため、間接的な呼び出しがいることは予測のコール仮想、ペナルティの一部ただし、またはPowerPCをターゲットにする場合は定義を考えPCゲームPC / Xbox 360のクロスプラットフォーム開発のベストプラクティス)。


12)

私は、コストの比較では、仮想関数呼び出しと直線関数呼び出しの間はないと思います。あなたは抽象基本クラス(インターフェイスを使用)について考えているなら、あなたは1つのいくつかのアクションのオブジェクトの動的な型を基に実行する状況がある。あなたはその選択何とかしなければならない。 1つのオプションは、仮想関数を使用することです。もう1つは、オブジェクトの種類にスイッチ、RTTIを(潜在的に高価な)、またはタイプ()基本クラス(潜在的に各オブジェクトのメモリ使用量を増加する方法)を追加するのいずれかを介して。仮想関数呼び出しのコストがだから何もしないのコストに代替のコストではなく、比較する必要があります。


13)

いくつかのケース別に適用される代わりに、コンパイル時のポリモーフィズムテンプレートです。これは例です。有用、ときには、で始まりの選択を実装する場合にプログラムし、実行の期間使用して、それを。ランタイムの多の例

class AbstractAlgo
{
    virtual int func();
};

class Algo1 : public AbstractAlgo
{
    virtual int func();
};

class Algo2 : public AbstractAlgo
{
    virtual int func();
};

void compute(AbstractAlgo* algo)
{
      // Use algo many times, paying virtual function cost each time

}   

int main()
{
    int which;
     AbstractAlgo* algo;

    // read which from config file
    if (which == 1)
       algo = new Algo1();
    else
       algo = new Algo2();
    compute(algo);
}

多コンパイル時に使用して同じ

class Algo1
{
    int func();
};

class Algo2
{
    int func();
};


template<class ALGO>  void compute()
{
    ALGO algo;
      // Use algo many times.  No virtual function cost, and func() may be inlined.
}   

int main()
{
    int which;
    // read which from config file
    if (which == 1)
       compute<Algo1>();
    else
       compute<Algo2>();
}

14)

はい、死刑です。お使いのプラットフォームのパフォーマンスを向上させることが何かは仮想関数を持つ非抽象クラスを使用することです。次に、非仮想関数をメンバ関数ポインタを使用します。


15)

ほとんどの人は実行時のペナルティと、当然のことを注意してください。

しかし、私の経験で大規模なプロジェクトに取り組んで、明確なインターフェイスと適切なカプセル化の恩恵はすぐに速度ゲインを相殺した。最終結果は、大規模な利得ですので、モジュールのコードが改善された実装のために、交換することができます。

あなたの燃費は異なる場合があります、それは明らかにあなたが開発しているアプリケーションに依存します。


16)

も参照してこのフォーラムを関数の仮想コストを説明します。




17)

複数の継承を注意してください複数のvtableのポインタを持つオブジェクトのインスタンスを肥大。 G + +でx86マシンにより、あなたのクラスは、仮想メソッドとは、基本クラスを持つ場合は、vtableのに1つのポインタがあります。あなたは仮想メソッドと1つの基本クラスがある場合は、まだvtableのに1つのポインタがあります。メソッドが仮想基本クラスを2つお持ちの場合は、 インスタンスへのポインタを上の各 vtableが持つ2つの

したがって、複数の継承(これは何であるかC + +でインターフェイスを実装している)を使えば、オブジェクトのインスタンスのサイズは基本クラス回ポインタのサイズをお支払いいただきます。メモリ使用量の増加は間接的なパフォーマンスへの影響があるかもしれません。


18)

私はそれは珍しい視点だが、知っても、私はあなたが多すぎるクラス構造に考えた方法を入れている疑いがあるなって、この問題に言及。私は方法をあまりにも多くの抽象化"の"レベルがあった多くのシステムを見てきたとそれだけで彼らが深刻なパフォーマンスの問題になりやすい、メソッド呼び出しのコストによるものではしたが、傾向が不要な呼び出しをしているため。レベル場合、複数の上、これが発生すると、それは致命的だ。取る顔は


19)

インターフェイスが実装にコールを渡す必要はありませんか?