6

ヘッダーで非メンバー関数を定義すると、コンパイラによって常にインライン化されますか?それともコンパイラはヒューリスティックに基づいて選択しますか? __inline は単なるヒントであることは知っていますが、ヘッダー内の関数と同じですか?

4

5 に答える 5

11

ヘッダーから何かを含めることは、ソースファイルに直接入力することと同じであることに注意してください。したがって、コンパイラーに関する限り、ヘッダーに含まれていても違いはありません。それがそこにあることを決して知りませんでした。

したがって、ヘッダーファイルで関数を定義し、そのヘッダーファイルをファイルにインクルードすると、関数をファイルに直接入力したようなものになります。だから今問題は、「コンパイラはヒューリスティックに基づいて物事をインライン化することを選択するのか?」です。

答えは「コンパイラによって異なります」です。この規格は、何がインライン化されるかについては保証しません。とは言うものの、最新のコンパイラーは、おそらくヒューリスティックを使用して、インライン化する内容について非常にインテリジェントになります。

しかし、興味深い点に到達しました。ヘッダーに関数があり、そのヘッダーを複数のソースファイルに含めるとします。これにより、変換単位全体で関数の複数の定義が作成され、これは単一定義規則に違反します。エルゴ、コンパイルエラーが発生します。(リンカエラーは通常、「エラー、関数xはyですでに定義されています」の行に沿ったものです)実行できることは、inlineキーワードを使用することであり、ODRに違反しなくなります。

ちなみに__inline非標準です。あなたの投稿とは反対に、それは通常、インライン化を強制するコンパイラ拡張であり、それを示唆するものではありません。inlineは標準のキーワードであり、元々はインライン化を示唆することを目的としていました。あなたが言うように、ほとんどの最近のコンパイラはその点でそれを完全に無視します、そしてそれは今日の唯一の目的は物事に内部リンクを与えることです。

于 2010-03-06T04:00:44.250 に答える
4

C ++ FAQ Liteから:

関数をインラインとして指定する方法に関係なく、コンパイラーが無視できるようにする要求です。インライン関数の呼び出しの一部、すべて、またはまったくをインライン展開する場合があります。

于 2010-03-06T04:03:01.643 に答える
2

ヒューリスティックに基づいて選択します。明示的にインラインとして宣言するようにしてください。そうしないと、ヘッダーを複数のコンパイル単位に含めると、重複するシンボルリンクエラーが発生する可能性があります。

于 2010-03-06T04:00:22.083 に答える
2

ヘッダーファイルで外部リンケージを使用して関数を定義し、それを複数の変換ユニットにインクルードすると、単一定義規則(ODR)に違反した場合にコンパイルエラー(より正確にはリンカーerorr)が発生します。したがって、答えは「いいえ」です。ヘッダーファイルで関数を定義することは、コンパイラーによってインライン化のヒントとして受け取られることはなく、ODRの要件を遵守することを免除されることもありません。このような関数がインライン化されることが保証されていないだけでなく、プログラムがコンパイルされない可能性があります。

ヘッダーファイルで関数を定義してそれを回避するには、内部リンケージを与えるか(宣言してstatic、各変換ユニットで個別の関数にする)、または明示的に宣言する必要がありinlineます。

ヒューリスティックに関しては...最近のコンパイラは、定義されている場所や明示的に宣言されているかどうかに関係なく、通常、(ヒューリスティックを適用することによって)インライン化するための実質的にすべての関数を考慮しinlineます。

于 2010-03-06T04:17:30.387 に答える
1

ヘッダーの関数には魔法はありません。コンパイラは、関数がヘッダーで定義されているかどうかさえ知りません。(ヘッダーは事実上、ソースファイルにコピー/貼り付けされるだけなので、ヘッダーで定義することもできますが、コンパイラーはそれを変換ユニットの一部と見なします)

注意すべき「インライン」には2つの異なる意味もあります。

関数は、C ++標準で定義されているようにインライン化できます。これは、関数の前にキーワードを付けるかinline、メンバー関数の場合はクラス定義内のインプレースで定義することによって行われます。

これの効果は

  • 複数のファイルで関数定義が発生する可能性があることをリンカに通知します。エラーをスローするのではなく、それらをサイレントにマージする必要があります。
  • コンパイラがインライン最適化を実行しやすくします。

一方、インライン最適化は、関数呼び出しを呼び出された関数の本体に置き換える行為です。つまり、この最適化は、関数ではなく呼び出しサイトに実際に適用されます。関数は通常、一部の場所で呼び出される場合がありますが、他の場所ではインライン化されます。関数呼び出しは、コンパイラーがそのように感じたときにインライン化されます。概念的には、「インライン」の最初の意味から完全に分離するのが最善です。

コンパイラーは、そのように感じた場合、いつ、どこでインライン最適化を適用します。これには多くのヒューリスティックを使用します。小さい関数はインライン化される可能性が高くなります。特定の呼び出しサイトが十分に頻繁に実行されると判断された場合、インライン化される可能性が高くなります。最終的に、それが使用するヒューリスティックは、「パフォーマンスを改善または低下させるか」に基づいています。そして、それは一般的に人間よりもこれをよりよく判断するので、それがどのような正確なヒューリスティックを使用しているかを実際に知る必要はありません。インライン化が多すぎると、パフォーマンスが低下するだけです。

于 2010-03-06T12:45:13.303 に答える