インラインはコンパイラへのヒントまたは要求であり、関数呼び出しのオーバーヘッドを回避するために使用されることは知っています。
それでは、関数がインライン化の候補であるかどうかをどのような根拠で判断できますか?どの場合、インライン化を避けるべきですか?
インラインはコンパイラへのヒントまたは要求であり、関数呼び出しのオーバーヘッドを回避するために使用されることは知っています。
それでは、関数がインライン化の候補であるかどうかをどのような根拠で判断できますか?どの場合、インライン化を避けるべきですか?
回答:
関数呼び出しのコストを回避することは、話の半分にすぎません。
行う:
inline
代わりに使用#define
inline
:より高速なコードと小さな実行可能ファイル(コードキャッシュにとどまる可能性が高くなります)しないでください:
ライブラリを開発する場合、将来クラスを拡張可能にするために、次のことを行う必要があります。
inline
キーワードはコンパイラーへのヒントであることを忘れないでください。コンパイラーは関数をインライン化しないことを決定する場合がありinline
、最初にマークされていない関数をインライン化することを決定する場合があります。通常、マーキング機能は避けますinline
(非常に小さな関数を書くときは別として)。
パフォーマンスについては、賢明なアプローチは(いつものように)アプリケーションをプロファイリングすることです。 inline
プロファイリングし的にはボトルネックを表す一連の関数をプロファイリングすることです。
参照:
編集:Bjarne Stroustrup、C ++プログラミング言語:
関数はと定義できます
inline
。例えば:
inline int fac(int n)
{
return (n < 2) ? 1 : n * fac(n-1);
}
inline
指定子は、それがの呼び出しのためのコードを生成しようとすべきであることをコンパイラへのヒントですfac()
一度関数のコードを敷設して、通常の関数呼び出しメカニズムを通じて呼び出すよりもインラインではなく。賢いコンパイラは720
、呼び出し用の定数を生成できますfac(6)
。相互に再帰的なインライン関数、入力に応じて再帰するかしないかに依存するインライン関数などの可能性により、inline
関数のすべての呼び出しが実際にインライン化されることを保証することが不可能になります。コンパイラーの賢さの程度を規定することはできません。そのため、あるコンパイラーが生成し720
、別のコンパイラーが、さらに別の6 * fac(5)
インライン化されていない呼び出しを生成する可能性がありますfac(6)
。異常に賢いコンパイルおよびリンク機能がない場合にインライン化を可能にするには、インライン関数の定義(宣言だけでなく)がスコープ内になければなりません(§9.2)。
inline
especifierは、関数の意味論に影響を与えません。特に、インライン関数は依然として一意のアドレスを持っているためstatic
、インライン関数の変数(§7.1.2)があります。
EDIT2:ISO-IEC 14882-1998、7.1.2関数指定子
指定子付きの関数宣言(8.3.5、9.3、11.4)は
inline
、インライン関数を宣言します。インライン指定子は、呼び出しの時点での関数本体のインライン置換が通常の関数呼び出しメカニズムよりも優先されることを実装に示します。呼び出しの時点でこのインライン置換を実行するための実装は必要ありません。ただし、このインライン置換を省略した場合でも、7.1.2で定義されているインライン関数の他のルールは引き続き尊重されます。
inline
コンパイラへのヒント以上のものです。複数の定義に関する言語規則を変更します。また、静的データがあることは、関数のインライン化を回避するための鋳鉄の理由ではありません。実装では、関数が宣言されているかどうかにかかわらず、各関数staticに単一の静的オブジェクトを割り当てるinline
必要があります。インラインコンストラクターと仮想デストラクタがある場合でも、クラスは拡張可能です。また、空のブレースデストラクタは仮想関数の1つであり、インラインのままにしておくことをお勧めします。
inline
、その結果、関数はインライン化されません。呼び出しの代金を支払うだけでなく、関数を含み、関数を呼び出す各翻訳単位は、コードと静的変数の独自のコピーを取得します。ライブラリの開発時にコンストラクタとデストラクタをインライン化しない理由は、ライブラリの将来のバージョンとのバイナリ互換性です
inline
コンパイラーがそのように感じた場合、非関数をインライン化できます。またinline
、コンパイラーがインライン化しないことを決定した場合、関数はインライン化されません。チャールズベイリーが言ったように、それは言語規則を変更します。それを最適化のヒントとして考えるのではなく、完全に異なる概念として考える方が正確です。このinline
キーワードは、複数の定義のみを許可するようコンパイラーに指示します。「インライン化」最適化は、マークされているかどうかに関係なく、ほとんどすべての関数に適用できますinline
。
inline
関数のインライン化を取得するためにすべてを使用するわけではありません。ODRを回避するなど、他の利点が必要になる場合があります。
inline
最適化とはほとんど関係がありません。 inline
与えられた定義がプログラム内で複数回発生した場合にエラーを生成しないようにコンパイラーに指示します。定義は、使用されるすべての変換で発生し、出現するすべての場所でまったく同じ定義になります。
上記のルールを考えると、inline
宣言が必要とするものに対する追加の依存関係を本文に含める必要がない短い関数に適しています。定義に遭遇するたびにそれを解析し、その本体のコードを生成する必要があるため、単一のソースファイルで1回だけ定義された関数に対するコンパイラオーバーヘッドが発生します。
コンパイラーは、選択した関数呼び出しをインライン化(つまり、関数の呼び出しをその関数のアクションを実行するコードに置き換える)できます。以前は、呼び出しと同じ変換単位で宣言されていない関数を「明らかに」インライン化できなかったが、リンク時間の最適化の使用が増えたため、これは今では真実ではない。同様に、マークされた関数inline
がインライン化されない可能性があることも事実です。
inline
キーワードとどのような関係がありますか?そして、幸せな偶然とは何ですか?
関数をインライン展開するようコンパイラーに指示することは最適化であり、最適化の最も重要なルールは、早期の最適化がすべての悪の根源であることです。常に明確なコードを記述し(効率的なアルゴリズムを使用)、プログラムのプロファイルを作成し、時間がかかりすぎる関数のみを最適化します。
特定の関数が非常に短くて単純で、内側の狭いループで何万回も呼び出される場合は、その関数が適している可能性があります。
ただし、驚くかもしれません-多くのC ++コンパイラーは小さな関数を自動的にインライン化します-そして、インライン化の要求も無視する可能性があります。
/FAcs
Visual Studio、-s
GCCで)生成するようにコンパイラーを設定して、コンパイラーが何をするかを正確に確認できます。私の経験では、これらのコンパイラはどちらもインラインキーワードの重みをかなり重視しています。
inline
キーワードの重み付けをまったくしていないので、興味深いです。つまり、インライン化されている関数を確認inline
し、そこから指定子を削除しても、関数はインライン化されます。反対の具体的な例がある場合は、それらを共有してください!
inline
キーワードは「明確なコード」をどのように妨げますか?「時期尚早の最適化」のキーワードは時期尚早であり、最適化ではありません。*最適化を積極的に避けるべきだと言っているのは、ごみです。その引用の要点は、必要ではない可能性のある最適化を避け、コードに有害な副作用(保守性を低下させるなど)を避ける必要があることです。inline
キーワードがコードの保守性を低下させる方法、または関数に追加することでどのように害を及ぼす可能性があるのか、私にはわかりません。
見つける最良の方法は、プログラムのプロファイルを作成し、何度も呼び出される小さな関数にマークを付けて、CPUサイクルをとして実行することinline
です。ここでのキーワードは「小さい」です。関数呼び出しのオーバーヘッドが関数で費やされた時間と比較して無視できるほどになると、それらをインライン化しても意味がありません。
私が提案する他の使用法は、キャッシュミスに関連するほど頻繁にパフォーマンスが重要なコードで呼び出される小さな関数がある場合、おそらくそれらもインライン化する必要があるということです。繰り返しになりますが、プロファイラーがそれを伝えることができるはずです。
時期尚早の最適化はすべての悪の根源です!
経験則として、私は通常「ゲッター」と「セッター」のみをインライン化します。コードが機能して安定すると、プロファイリングにより、インライン化のメリットが得られる関数を特定できます。
一方、最新のコンパイラのほとんどは非常に優れた最適化アルゴリズムを備えており、インライン化する必要があるものをインライン化します。
復活-インラインの1行関数を記述し、後で他の関数について心配する。
インラインを使用するかどうかを決定するときは、通常、次のことを念頭に置いてください。最新のマシンでは、メモリ遅延は生の計算よりも大きなボトルネックになる可能性があります。頻繁に呼び出されるインライン関数は、実行可能ファイルのサイズが大きくなることが知られています。さらに、そのような関数はCPUのコードキャッシュに格納でき、そのコードにアクセスする必要があるときにキャッシュミスの数を減らすことができます。
したがって、自分で決める必要があります。インライン化によって、生成されるマシンコードのサイズが増加または減少しますか?関数を呼び出すとキャッシュミスが発生する可能性はどのくらいありますか?コード全体にペッパーが付いている場合、可能性は高いと言えます。単一のタイトループに制限されている場合、可能性は低くなるはずです。
私は通常、以下にリストするケースではインライン化を使用します。ただし、パフォーマンスに本当に関心がある場合は、プロファイリングが不可欠です。さらに、コンパイラーが実際にヒントを取得するかどうかを確認することもできます。
また、インラインメソッドは、大規模なプロジェクトを維持するときに重大な副作用があります。インラインコードが変更されると、それを使用するすべてのファイルがコンパイラーによって自動的に再ビルドされます(これは優れたコンパイラーです)。これは開発時間の多くを無駄にする可能性があります。
ときinline
の方法は、ソース・ファイルに転送し、任意のより多くのインライン化されていない、プロジェクト全体は(少なくともこれは私の経験をされている)を再構築する必要があります。また、メソッドがインラインに変換される場合も同様です。
inline
は関係ありません(inline
キーワードがない場合を除いて、リンカーエラーが発生しますが、inline
キーワードは過剰な再構築を引き起こす問題ではありません。)
私はいくつかの回答を読みましたが、不足しているものがいくつかあります。
私が使用するルールは、インラインにしたくない限り、インラインを使用しないことです。ばかげて見える、今の説明。
コンパイラーは十分にスマートで、短い関数は常にインラインになります。そして、プログラマーがそうするように言わない限り、長い関数をインラインとして機能させないでください。
インラインはコンパイラへのヒントまたは要求であることを知っています
実際にinline
はコンパイラの順序であり、選択肢はなく、inline
キーワードの後はすべてのコードをインラインにします。したがって、inline
キーワードを使用することはできません。コンパイラは最短のコードを設計します。
だからいつ使うのinline
?
コードをインライン化したい場合に使用します。1つの状況でしか使用しないので、私は1つの例しか知りません。ユーザー認証です。
たとえば、私はこの機能を持っています:
inline bool ValidUser(const std::string& username, const std::string& password)
{
//here it is quite long function
}
この関数がどれほど大きい場合でも、ソフトウェアをクラックしにくくするため、インラインとして使用したいと考えています。
inline
CFLAGS
Gentooの初心者-O3 -funroll-loops -finline-functions