インライン関数はいつ使用し、いつ使用しない方が良いですか? [重複] 質問する

インライン関数はいつ使用し、いつ使用しない方が良いですか? [重複] 質問する

インラインはコンパイラへのヒントまたは要求であり、関数呼び出しのオーバーヘッドを回避するために使用されることは知っています。

では、関数がインライン化の候補であるかどうかをどのような基準で判断できるでしょうか? どの場合にインライン化を避けるべきでしょうか?

ベストアンサー1

関数呼び出しのコストを回避することは、話の半分にしか過ぎません。

する:

  • inline代わりに使用する#define
  • 非常に小さな関数は、次の点で優れていますinline: コードの高速化と実行ファイルの小型化 (コード キャッシュに残る可能性が高くなります)
  • 関数は小さく頻繁に呼び出される

しないでください:

  • 大きな関数: 実行ファイルが大きくなり、呼び出しのオーバーヘッドによる実行速度の向上にもかかわらず、パフォーマンスが大幅に低下します。
  • I/Oバウンドのインライン関数
  • この機能はほとんど使用されない
  • コンストラクタとデストラクタ: 空の場合でも、コンパイラはそれらのコードを生成します。
  • ライブラリを開発する際にバイナリ互換性が失われる:
    • 既存の関数をインライン化する
    • インライン関数を変更するか、インライン関数を非インラインにする: ライブラリの以前のバージョンは古い実装を呼び出します

ライブラリを開発する際に、将来クラスを拡張可能にするには、次の点に注意する必要があります。

  • 本体が空の場合でも非インライン仮想デストラクタを追加する
  • すべてのコンストラクタを非インラインにする
  • クラスが値によってコピーできない場合を除いて、コピーコンストラクタと代入演算子の非インライン実装を記述する

キーワードはコンパイラへのヒントであることに注意してください。コンパイラは関数をインライン化しないことを決定する場合もあれば、最初にinlineマークされなかった関数をインライン化することを決定する場合もあります。私は通常、関数をマークすることを避けます(非常に小さな関数を記述する場合を除く)。inlineinline

パフォーマンスに関しては、(いつものように) アプリケーションをプロファイリングし、最終的にinlineボトルネックを表す一連の関数をプロファイリングするのが賢明なアプローチです。

参考文献:


編集: Bjarne Stroustrup、C++ プログラミング言語:

関数は と定義できますinline。例:

inline int fac(int n)
{
  return (n < 2) ? 1 : n * fac(n-1);
}

指定子は、関数のコードを一度記述してから通常の関数呼び出しメカニズムで呼び出すのではなく、 inlineinlineの呼び出しのコードを生成するようにコンパイラに指示するヒントです。 賢いコンパイラは、呼び出しの定数を生成できます。 相互に再帰的なインライン関数、入力に応じて再帰するかどうかが決まるインライン関数などが存在する可能性があるため、関数のすべての呼び出しが実際にインライン化されることを保証することは不可能です。 コンパイラの賢さの度合いを規定することはできないため、あるコンパイラは を生成し、別のコンパイラは を生成し、さらに別のコンパイラはインライン化されていない呼び出し を生成する可能性があります。fac()720fac(6)inline7206 * fac(5)fac(6)

非常に巧妙なコンパイルおよびリンク機能がなくてもインライン化を可能にするには、インライン関数の宣言だけでなく定義もスコープ内になければなりません (§9.2)。エスケープ指定子はinline関数のセマンティクスには影響しません。特に、インライン関数には一意のアドレスがあり、インライン関数の変数にも一意のアドレスがありますstatic(§7.1.2)。

編集2: ISO-IEC 14882-1998、7.1.2 関数指定子

指定子付きの関数宣言 (8.3.5、9.3、11.4) は、inlineインライン関数を宣言します。インライン指定子は、呼び出し時点での関数本体のインライン置換が通常の関数呼び出しメカニズムよりも優先されることを実装に示します。実装では、呼び出し時点でこのインライン置換を実行する必要はありません。ただし、このインライン置換が省略された場合でも、7.1.2 で定義されているインライン関数のその他のルールは尊重されます。

おすすめ記事