38

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

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

結論

どうやら、インライン関数を使用しても問題はありません。

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

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

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

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

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

4

13 に答える 13

21

inline キーワードは、実際にはコンパイラへのヒントにすぎないことに注意してください。コンパイラはインラインを無視し、どこかで関数のコードを生成するだけです。

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

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

于 2008-09-13T20:38:49.460 に答える
14

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

関数のステートメントが 1 つまたは 2 つだけであれば、通常は問題ないと思います。

編集: Linux CodingStyleドキュメントがそれについて述べていることは次のとおりです。

第15章 インライン病

gcc には「インライン」と呼ばれる魔法の「高速化」高速化オプションがあるという一般的な誤解があるようです。インラインの使用は適切な場合もありますが (たとえば、マクロを置き換える手段として。第 12 章を参照)、そうでない場合が非常に多くあります。inline キーワードを多用すると、カーネルが大幅に大きくなり、CPU の icache フットプリントが大きくなり、ページキャッシュに使用できるメモリが少なくなるため、システム全体が遅くなります。考えてみてください。ページキャッシュ ミスが発生するとディスク シークが発生しますが、これには 5 ミリ秒かかります。これらの 5 ミリ秒に入ることができる CPU サイクルはたくさんあります。

妥当な経験則として、3 行を超えるコードを含む関数をインライン化しないことです。このルールの例外は、パラメーターがコンパイル時の定数であることがわかっている場合です。この定数の結果として、コンパイラーはコンパイル時にほとんどの関数を最適化できることがわかっています。この後者のケースの良い例については、kmalloc() インライン関数を参照してください。

スペースのトレードオフがないため、静的で一度だけ使用される関数にインラインを追加することは常に有利であると主張する人がよくいます。これは技術的には正しいのですが、gcc はヘルプなしでこれらを自動的にインライン化することができます。また、2 番目のユーザーが現れたときにインラインを削除するというメンテナンスの問題は、gcc に何かを実行するように指示するヒントの潜在的な価値よりも重要です。

于 2008-09-13T20:28:46.020 に答える
5

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

于 2008-09-15T22:20:03.083 に答える
4

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

  • inline は、コンパイラが行うため不要な場合があります
  • インラインはコードを肥大化させる可能性があります

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

class OtherObject;

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

インラインがなければ、必要なのは OtherObject の前方宣言だけでした。インラインでは、ヘッダーに OtherObject の定義が必要です。

于 2008-09-13T22:28:06.857 に答える
4

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

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

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

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

于 2008-09-14T12:26:59.947 に答える
2

私の答えが質問に関連しているかどうかはわかりませんが、次のようになります。

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

于 2008-09-16T07:35:02.500 に答える
2

疑わしい。コンパイラでさえ、最適化のためにいくつかの関数を自動的にインライン化します。

于 2008-09-13T20:26:12.250 に答える
1

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

インライン化によってパフォーマンスが向上するのに十分なほど関数が小さい場合を判断するのは、非常に注意が必要です。Google の C++ スタイル ガイドでは、10 行以下のインライン関数のみを推奨しています。

(簡体字):

関数「X」を 5 回呼び出すだけの単純なプログラムを想像してみてください。

X が小さく、すべての呼び出しがインライン化されている場合: 1 回のメイン メモリ アクセスですべての命令が命令キャッシュにプリフェッチされる可能性があります。

X が大きい場合、命令キャッシュの容量に近づいているとしましょう。X をインライン化すると、X
のインライン インスタンスごとにメモリから命令が 1 回
フェッチされる可能性があります。X がインライン化されていない場合、命令は最初の呼び出しでメモリからフェッチされる可能性があります。 X に変換されますが、後続の呼び出しのためにキャッシュに残る可能性があります。

于 2008-09-14T11:58:54.147 に答える
1

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

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

VC++ コンパイラを使用すると、この決定をオーバーライドできます。__forceinline

一般的には、ヘッダーに関数を入れたい場合はインラインを使用しますが、それ以外の場所ではほとんど意味がありません.

于 2008-09-13T20:41:07.817 に答える
0

私が見たインライン関数の他の問題の中で、非常に乱用されている (500 行のインライン関数を見てきました) 中で、注意する必要があるのは次のとおりです。

  • ビルドの不安定性

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

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

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

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

于 2016-07-25T08:34:55.760 に答える
0

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

于 2008-09-13T20:31:27.403 に答える