インライン関数を使用すると何が問題になるのでしょうか?

StackOverflow https://stackoverflow.com/questions/60830

  •  09-06-2019
  •  | 
  •  

質問

状況によってはインライン関数を使用すると非常に便利ですが、

インライン関数には欠点はありますか?

結論:

どうやら、インライン関数を使用することに何も問題はありません。

ただし、次の点に注意してください。

  • インラインを過度に使用すると、実際にはプログラムが遅くなる可能性があります。関数のサイズに応じて、関数をインライン化するとコード サイズが増減する可能性があります。非常に小さなアクセサー関数をインライン化すると、通常はコード サイズが小さくなりますが、非常に大きな関数をインライン化すると、コード サイズが大幅に増加する可能性があります。最新のプロセッサでは、通常、命令キャッシュが適切に使用されるため、より小さなコードの方が高速に実行されます。 - Google ガイドライン

  • インライン関数の速度上の利点は、関数のサイズが大きくなるにつれて減少する傾向があります。ある時点で、関数呼び出しのオーバーヘッドが関数本体の実行に比べて小さくなり、利点が失われます。 - ソース

  • インライン関数が機能しない状況がいくつかあります。

    • 値を返す関数の場合。return ステートメントが存在する場合。
    • 値を返さない関数の場合。ループ、switch、または goto ステートメントが存在する場合。
    • 関数が再帰的である場合。 -ソース
  • __inline キーワードにより、最適化オプションを指定した場合にのみ関数がインライン化されます。optimize が指定されている場合、 __inline インライン オプティマイザー オプションの設定に応じて優先されます。デフォルトでは、インライン オプションはオプティマイザが実行されるたびに有効になります。optimize を指定する場合、必要に応じて noinline オプションも指定する必要があります。 __inline 無視されるキーワード。 -ソース

役に立ちましたか?

解決

inline キーワードは実際にはコンパイラへの単なるヒントであることを指摘しておきます。コンパイラはインラインを無視し、単に関数のコードをどこかに生成する場合があります。

インライン関数の主な欠点は、 実行可能ファイルのサイズを増やす (インスタンス化の数によって異なります)。これは一部のプラットフォーム (例:組み込みシステム)、特に関数自体が再帰的である場合。

インライン関数を作成することもお勧めします 非常に少ない - インライン関数の速度の利点は、関数のサイズが大きくなるにつれて減少する傾向があります。ある時点で、関数呼び出しのオーバーヘッドが関数本体の実行に比べて小さくなり、利点が失われます。

他のヒント

実行可能ファイルのサイズを増やす可能性があり、インラインキーワードを使用しても、コンパイラーが実際にインラインになるとは思いません。(またはそれは何のように逆ですか ヴァイバブ言った?...)

関数に1つまたは2つのステートメントしかない場合は、通常大丈夫だと思います。

編集: Linuxとは次のとおりです コーディングスタイル 文書にはそれについて次のように書かれています。

第15章:インライン病

GCCには「インライン」と呼ばれる魔法の「Make Me Faster」スピードアップオプションがあるという一般的な誤解があるようです。インラインの使用は適切な場合がありますが(たとえば、マクロを置き換える手段として、第12章を参照)、そうではないことが非常によくあります。インラインキーワードの豊富な使用は、CPUのICACHEフットプリントが大きいため、PageCacheのメモリが少ないために、システム全体を減速させるはるかに大きなカーネルにつながります。ちょっと考えてみてください。Pagecache Missはディスクシークを引き起こし、5ミリ秒かかります。これらの5つのミリ秒に入ることができる多くのCPUサイクルがあります。

合理的な経験則は、3行以上のコードを含む関数にインラインを付けないことです。このルールの例外は、パラメーターがCompiletime Constantであることが知られている場合、そしてこの定期性の結果としてあなたが 知る コンパイラは、コンパイル時にほとんどの機能を最適化できます。この後のケースの良い例については、kmalloc()インライン関数を参照してください。

多くの場合、人々は、静的で一度だけ使用される関数にインラインを追加することは、スペーストレードオフがないため、常に勝利であると主張します。これは技術的には正しいものですが、GCCはこれらを助けなく自動的に導入することができます。また、2番目のユーザーが見えるときにインラインを削除するメンテナンスの問題は、GCCにとにかく行ったことをするように指示するヒントの潜在的な値を上回ることができます。

私は他の投稿に同意します:

  • inline はコンパイラが行うので不要かもしれません
  • インラインだとコードが肥大化する可能性がある

3 番目のポイントは、ヘッダーで実装の詳細を公開することが強制される可能性があることです。

class OtherObject;

class Object {
public:
    void someFunc(OtherObject& otherObj) {
        otherObj.doIt(); // Yikes requires OtherObj declaration!
    }
};

インラインを使用しない場合、必要なのは OtherObject の前方宣言だけでした。インラインを使用すると、ヘッダーにはotherObjectの定義が必要です。

他の人が述べたように、inline キーワードはコンパイラへのヒントにすぎません。実際、最新のコンパイラのほとんどはこのヒントを完全に無視します。コンパイラには、関数をインライン化するかどうかを決定する独自のヒューリスティックがあり、率直に言って、あなたのアドバイスを望んでいません。ありがとうございます。

本当に本当に何かをインラインで作成したい場合、実際にプロファイリングして逆アセンブリを調べて、コンパイラのヒューリスティックをオーバーライドすることが実際に意味があることを確認していれば、次のことが可能です。

  • VC++ では、__forceinline キーワードを使用します。
  • GCC では、__attribute__((always_inline)) を使用します。

ただし、inline キーワードには 2 番目の有効な目的があります。それは、クラス定義内ではなくヘッダー ファイル内で関数を宣言することです。inline キーワードは、関数の複数の定義を生成しないようにコンパイラーに指示するために必要です。

インラインには問題があります。ヘッダー ファイルで関数を定義すると (明示的またはクラス内のメンバー関数の本体を定義することで暗黙的にインラインを意味します)、ユーザーに再コンパイルを強制せずに関数を変更する簡単な方法はありません。 (再リンクとは対照的に)。これは、特に問題の関数がライブラリで定義されており、ヘッダーがそのインターフェイスの一部である場合に問題を引き起こすことがよくあります。

私はそれを疑う。コンパイラでも、最適化のために一部の関数が自動的にインライン化されます。

私の答えが質問に関係しているかどうかはわかりませんが、次のとおりです。

なれ とても インライン仮想メソッドには注意してください。一部のバグのあるコンパイラ (たとえば、Visual C++ の以前のバージョン) は、標準の動作が継承ツリーを下って適切なメソッドを呼び出すことだけを行う仮想メソッドのインライン コードを生成します。

より大きな関数をインライン化するとプログラムが大きくなり、キャッシュミスが増えて速度が遅くなる可能性があります。

関数が十分小さい場合にインライン化することでパフォーマンスが向上するかを判断するのは非常に困難です。 Google の C++ スタイル ガイド 10 行以下の関数のみをインライン化することをお勧めします。

また、inline キーワードは単なるリクエストであることにも注意してください。コンパイラーは、速度とサイズのトレードオフに価値があると判断した場合、インラインとして定義しなかった関数をインライン化しないことを選択する場合があります。

この決定は通常、速度の最適化 (関数呼び出しを回避する) とサイズの最適化 (インライン化はコードの肥大化を引き起こす可能性があるため、繰り返し使用される大規模な関数には適していません) の間の設定など、さまざまな事項に基づいて行われます。

VC++ コンパイラーを使用すると、次のようにしてこの決定を上書きできます。 __forceinline

一般的に:本当にヘッダーに関数を入れたい場合はインラインを使用しますが、それ以外の場所ではほとんど意味がありません。なぜなら、そこから何かを得ようとするなら、優れたコンパイラーがいずれにせよ関数をインライン化してくれるからです。

関数を過剰にインライン化すると、コンパイルされた実行可能ファイルのサイズが増加し、キャッシュのパフォーマンスに悪影響を与える可能性がありますが、最近ではコンパイラーは関数のインライン化を独自に (多くの基準に応じて) 決定し、inline キーワードを無視します。

インライン関数に関する他の問題のうち、私が頻繁に使いすぎているのを見たことがあります (500 行のインライン関数を見たことがあります)。特に注意しなければならないのは次のとおりです。

  • ビルドの不安定性

    • インライン関数のソースを変更すると、ヘッダーのすべてのユーザーが再コンパイルされます。
    • #includeクライアントに漏洩します。インライン関数を再加工し、一部のクライアントが依存していた使用されなくなったヘッダーを削除する場合、これは非常に厄介な問題になる可能性があります。
  • 実行可能ファイルのサイズ

    • 呼び出し命令の代わりにインラインがインライン化されるたびに、コンパイラーはインラインのコード全体を生成する必要があります。関数のコードが短い (1 行または 2 行) 場合はこれで問題ありませんが、関数が長い場合はあまり良くありません。
    • 一部の関数は、最初に表示されるよりもはるかに多くのコードを生成することがあります。その好例は、多くのポッド以外のメンバー変数 (またはかなり乱雑なデストラクターを持つ 2 つまたは 3 つのメンバー変数) を持つクラスの「簡単な」デストラクターです。呼び出しを生成する必要があります それぞれ デストラクター。
  • 実行時間

    • これは CPU キャッシュと共有ライブラリに大きく依存しますが、参照の局所性は重要です。インライン化しているコードがたまたま CPU キャッシュ内の 1 か所に保持されている場合、多くのクライアントは、キャッシュ ミスやその後のメモリ フェッチ (さらに悪いことに、ディスク フェッチ) の影響を受けないコードを見つけることができます。 。残念ながら、これは本当にパフォーマンス分析を行う必要があるケースの 1 つです。

私が取り組んでいるコーディング標準では、インライン関数を単純なセッター/ゲッターに制限しており、インライン化が顕著な利点をもたらすことを示すパフォーマンス測定がない限り、デストラクターをインライン化すべきではないと特に規定しています。

  1. 他の人が言ったように、コードが大きい場合、インライン関数は問題を引き起こす可能性があります。各命令は特定のメモリ位置に格納されるため、インライン関数のオーバーロードにより、コードの実行に時間がかかります。

  2. インラインが機能しない状況は他にもほとんどありません

    1. 再帰関数の場合は機能しません。
    2. 静的変数では機能しない場合もあります。
    3. また、ループやスイッチなどが使用されている場合や、複数のステートメントを使用している場合にも機能しません。
    4. また、関数 main はインライン関数として動作できません。
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top