ヘッダーで定義された関数はインライン化されることが保証されていますか?
質問
ヘッダーで非メンバー関数を定義した場合、その関数は常にコンパイラーによってインライン化されますか、それともコンパイラーがヒューリスティックに基づいて選択するのでしょうか?__inline は単なるヒントであることはわかっていますが、ヘッダー内の関数についても同じでしょうか?
解決
ヘッダから何かを含むことがちょうどソースファイルに直接入力するよりも違いはありませんことを覚えておいてください。だから、ヘッダであることはこれまで、コンパイラが懸念しているとしても違いはありません。それはそこに知っていたことはありません。
あなたは、ヘッダーファイル内の関数を定義して、あなたは、ファイル内のそのヘッダーファイルをインクルードするときにちょうどまっすぐファイルに関数を入力したように、だから、それはです。だから今の質問で、「コンパイラは、経験則に基づいて、インラインのものに選ぶのですか?」
答えは「それはコンパイラに依存」です。標準では、インライン化かを取得しますかについて保証しません。言った、現代の任意のコンパイラは、それはおそらく経験則で、インラインかについて非常にインテリジェントになります。
しかし、我々は興味深いポイントに来ます。想像してみて、あなたは、ヘッダー内の機能を持っていて、複数のソースファイルでそのヘッダが含まれています。その後、翻訳単位間で、関数の複数の定義を持つことになり、これは1-定義ルールに違反します。エルゴは、コンパイルエラーが発生します。 (リンカエラーは通常の線に沿って何かである:「エラー、機能がすでにYで定義されたX」)を行うことができますどのようなものですが、inline
キーワードを使用しないと、あなたは、もはやODRに違反する
__inline
により、は非標準です。あなたのポストに反して、それがの力をコンパイラの拡張機能は、通常のはインライン化ではなく、それをヒント。 inline
はもともとインライン化を示唆することを意図していた標準のキーワードです。あなたが言うように、最も近代的なコンパイラは完全にその点で、それを無視して、それが、今日唯一の目的だが、物事に内部リンケージを与えることです。
他のヒント
あなたが機能を指定する方法どんなに インラインとして、それが要求されます コンパイラは無視することが許可されている:それは インライン展開されますいくつかの、全て、またはnoneを インライン関数の呼び出します。
これは、経験則に基づいて選択されます。あなたは、複数のコンパイル単位でヘッダーを含める場合はそうでなければ、重複したシンボルのリンクエラーが発生することがありますインラインとして明示的にそれを宣言していることを確認します。
は、のヘッダファイルに外部リンケージを持つの関数を定義して、コンパイルエラー(より正確には:リンカerorr)を取得します、複数の翻訳単位にそれを含めると一つの定義の違反のためにルール(ODR)。ヘッダファイルに関数を定義するインライン化のヒントとして、コンパイラによって取られないであろうとODRの要件を観察するからあなたを言い訳しません。答えは「ノー」ですので。だけでなく、そのような関数がインライン化されることが保証されていませんが、ほとんどの場合、あなたのプログラムもコンパイルされません。
ヘッダ・ファイルに関数を定義し、あなたはどちらかそれを内部リンケージを与える必要があり、それに逃げるために(それはstatic
宣言し、各翻訳単位で独立した機能で終わる)、または明示的にそれがinline
宣言する。
としては、ヒューリスティックのために...現代のコンパイラは正常にかかわらず、それが定義されている場所の、それが明示的inline
を宣言されているかどうか、(ヒューリスティックを適用して)インライン化のための事実上すべての機能を検討します。
ヘッダー内の関数には魔法はありません。コンパイラは、関数がヘッダーに定義されているかどうかさえ知りません。(ヘッダーは事実上ソース ファイルにコピー/ペーストされるだけなので、ヘッダー内で定義することもできますが、コンパイラーはそれを翻訳単位の一部として認識するだけです)
また、「インライン」には 2 つの異なる意味があることに注意してください。
関数は次のとおりです。 インライン化された C++ 標準で定義されているとおり:これは、関数の前に次の接頭辞を付けることによって行われます。 inline
キーワードを使用するか、メンバー関数の場合は、クラス定義内のインプレースで定義します。
これによる効果は、
- 複数のファイルに関数定義が存在する可能性があるため、エラーをスローするのではなく、黙ってそれらをマージする必要があることをリンカーに通知します。
- コンパイラがインライン化を実行しやすくする 最適化.
インライン展開 最適化 一方、これは単に関数呼び出しを呼び出される関数の本体で置き換える行為です。つまり、この最適化は実際には関数ではなく呼び出しサイトに適用されます。関数は通常、ある場所では呼び出されますが、別の場所ではインライン化される場合があります。関数呼び出しは、コンパイラーがインライン化したいと判断した場合にインライン化されます。概念的に、これを「インライン」の最初の意味から完全に分離することが最善です。
コンパイラーは、必要に応じて、いつ、どこでインライン化の最適化を適用します。これには多くのヒューリスティックが使用されます。小さな関数はインライン化される可能性が高くなります。特定の呼び出しサイトが十分な頻度で実行されると判断された場合、その呼び出しサイトはインライン化される可能性が高くなります。最終的に、使用されるヒューリスティックは、「パフォーマンスが向上するか低下するか」に基づいています。そして、それは通常、人間よりもこのことをより適切に判断できるため、それがどのような正確なヒューリスティックを使用しているかを実際に知る必要はありません。インライン化が多すぎると、パフォーマンスが損なわれるだけです。