2

私の実装ファイル (.cc ファイル) では、クラス定義 (Pimpl クラスの関数など) でメンバー関数を定義すると便利であることがよくあります。例えば:

struct X::Impl {
    void DoSomething() {
        ...
    }
};

それ以外の

struct X::Impl {
    void DoSomething();
};

void X::Impl::DoSomething() {
    ...
}

これは、いくつかの理由から、クラス定義の外で関数を実装するよりも望ましいと思います。可読性を高め、メソッドを小さく保つ練習を容易にします (メソッドを簡単に追加できるようにすることで)。メソッド宣言を更新する必要がないため、コードの保守も簡単です。

唯一の欠点は、クラス宣言で定義されたメソッドが暗黙的にインライン化されることです。これは、オブジェクト コードのサイズが大きくなるため、通常は望ましくありません。

私の質問は次のとおりです。

  1. 私はこれの権利を持っていますか?私が見逃しているこのプラクティスの他の欠点はありますか?

  2. 暗黙のインライン展開は心配する必要がありますか? コンパイラは、インライン化されるべきではないメソッドをインライン化するという暗黙の要求を拒否するほどスマートですか?

  3. クラス定義で定義されたメソッドがインライン化されていないと宣言することは可能ですか?

4

4 に答える 4

3

簡単な答えは、気にする必要はないということです。クラス定義内で定義されたメンバー関数は暗黙的に ですが、インライン化inlineされているという意味ではありません(つまり、呼び出しの場所でコードをインライン化する必要はありません)。

コンパイラの実装者は、関数のサイズ、複雑さ、およびインライン化できるかどうか (再帰的関数はインライン化できません[*] )。コンパイラは、生成されたコードとそれが実行されるアーキテクチャについて、私たちのほとんどよりも多くの情報を持っています。信頼して、問題があると思われる場合はプロファイリングし、プロファイリングでコードを変更する必要があることが示された場合は変更を行いますが、事後に十分な情報に基づいた決定を下してください。

関数が実際にインライン化されているかどうかを確認したい場合は、アセンブリを見て、関数への呼び出しがあるかどうか、またはコードが実際にインライン化されているかどうかを確認できます。


[*]末尾再帰の場合のように、コンパイラが再帰を反復に変換できる場合、変換された関数は理論的にはインライン化できます。ただし、ループを含む関数は、とにかくインライン化される可能性が低くなります...

于 2012-06-01T23:40:53.260 に答える
2

インライン化を防ぐ移植可能な方法はわかりませんが、GCC では属性を使用できます。例えば:

struct X::Impl {
    void DoSomething() __attribute__((noinline)) {
        ...
    }
};
于 2012-06-01T23:23:31.260 に答える
0

インライン化の選択によって節約されるすべての CPU 時間を合計します。それらにあなた自身のそれよりも少ない支出をしてください。線形パス長の懸念は、現在、1 日に数兆回の実行を処理するパスに関するものです。L1 の 1 秒あたり 40 億で十分です。5分ではない250回。誰もパフォーマンスについて文句を言わないのであれば、あなたとあなたのコンパイラーの選択は少なくとも正しいリーグでプレーしている.

読みやすさに関する意見は大きく異なります。重要なのは聴衆の意見です。

于 2012-06-01T23:44:57.117 に答える
0

inline一般に、コンパイラは好きなようにインライン展開し、プログラマが指定したキーワードにはあまり注意を払いません。inlineは通常、 とほぼ同じように扱われstaticます。

たとえば、再帰関数は通常、完全にインライン化することはできません (インライン化する関数本体には、インライン化する必要がある呼び出しが再び含まれます)。特定のコンパイラの動作をテストするには、たとえば次のようなクラスを定義できます。

class Fib {
public:      
   int calc(int i);
};

int Fib::calc(int i) {
  if (i > 1)
     return calc(i-1) + calc(i-2);
  return 1;
}

この定義では、次のようなサンプル プログラムは、コンパイラが へのすべての呼び出しをインライン化する義務があると感じる場合、適切な時間またはサイズでコンパイルできませんcalc

#include "tst.hpp"
#include <iostream>                
int main() {
   Fib f;
   std::cout << f.calc(1000) << std::endl;
};

したがって、このプログラムをコンパイルすることで、コンパイラの動作をテストできます。コンパイルが成功した場合、コンパイラは へのすべての呼び出しをインライン化しませんでしたFib::calc

于 2012-06-01T23:46:58.510 に答える