2009-12-07 10 views
5

クラスのヘッダーファイル内でC++関数を定義すると関数がインラインになることを知りました。しかし、関数の隣にインライン・キーワードを置くことは単なる示唆に過ぎず、コンパイラは必ずしもそれに従わないことを知っています。これはヘッダーで定義されたC++関数と同じですか?また、スタンドアロンのC++関数とクラスの一部であるC++関数間の動作に違いがありますか?ヘッダー内に関数を定義すると、コンパイラーは常にインラインと見なしますか?

答えて

15

真実ではない

「クラスのヘッダファイル内のC++関数を定義するには、関数をインラインを作ります」。クラス定義の中で関数を定義する(つまり、宣言の代わりに関数の本体を提供する)ことはインラインにします。 「インラインにする」とは、インラインキーワードを与えることと同じ意味です。しかし、クラス定義はヘッダーにある必要はなく、ヘッダーにはクラス定義以外のものも含めることができます。

この例では、関数fooは暗黙的にインラインです。 barが暗黙のうちに、インラインではありません機能:

struct Foo { 
    void foo() {} 
    void bar(); 
}; 

void Foo::bar() {} 

inlineは二つの効果を持っている「機能の隣にinlineキーワードを入れては文句を言わない、必ずしもそれに従うだけの提案およびコンパイラです」。そのうちの1つは、無視できるコンパイラに対するヒントです。もう一方はオプションではなく、常にその効果があります。 「ヒント」は、コンパイラがその関数への呼び出しを関数自体のコードのコピーに置き換えることを推奨していることです。

複数の翻訳単位でインライン関数を定義でき、複数の定義エラーを伴わずにリンクされ、リンカーによってコピーの1つを除くすべてが削除されます。したがって、上記の例が複数の翻訳単位で共有されるヘッダーファイルに表示される場合は、barを明示的にインラインでマークする必要があります。そうしないと、リンカーはbarの複数の定義を検出しますが、これは許可されていません。

名前にもかかわらず、C++のinlineはほとんどの場合、第2の強制的な効果であり、第1のオプションのものではありません。現代の最適化コンパイラは、どの呼び出しがインライン化されるべきかについて独自のアイデアを持っており、その決定を下すときにはinlineに多くの注意を払っていません。例えば、私は中程度の最適化レベルではgccに影響があると見てきましたが、低レベルでは何もインライン化されておらず、高レベルでは関数を作らない限り(呼び出しがコンパイルされたときに定義が利用可能な場合)大きすぎる。

関数がヘッダーまたはcppファイルで定義されているかどうかは、単独では何も影響しません。 #includeが行うことは、コンパイラがそれを見る前に、ヘッダファイルをコピーしてプリプロセッサのcppファイルに貼り付けることです。同じ変換単位で関数が呼び出されたときに関数が定義されている場合、その関数コードはコンパイラーによってインライン化されます。それらが異なる翻訳単位にある場合、コードは利用できず、コールはリンカーによってインライン化され、プログラム全体の最適化または同様のものでしかない。多分、「翻訳単位」とは、「すべてのヘッダーがコピーされて貼り付けられた後のcppファイル」を意味します。

+1

+1は 'inline'キーワードの2番目の効果に言及しています。 –

3

C++コンパイラは、どのようなヒントを与えてもインラインになるものとできないものを自由に選択できます。関数がクラスの一部であるかどうか、またはそれがヘッダファイルかソースファイルのどちらにあるかは重要ではありません。コンパイラはその決定を下す際にそれらの事柄に注意を払わない。

+1

正確には、コンパイラは、定義されていない関数をインライン化することはできません。これは、関数がインクルードされたヘッダーで宣言されていて、別のコンパイル単位で定義されている場合です。ただし、そのような最適化をサポートしている場合、リンカは関数をインライン展開することもできます。 –

+0

@Carl:本当ですが、質問は反対の条件についてでした。私の答えはもう少し慎重に語られているはずです。 –

0

フリーのテンプレート以外の関数の定義をヘッダーファイルに配置すると、ヘッダーを含む各.cppファイルの関数定義が(直接的または間接的に)終了します。これはリンク時に問題を引き起こす可能性があります。

ただし、関数をインラインに宣言すると、リンカーは複数の場所に含まれていても1つの定義のみを使用します。

1

いいえ、必ずしもそうではありません。コンパイラはinlineキーワードのようにヒントとして扱いますが、コストやメリットがどのようなものかよく分かっているので、ほとんどは独自に決定します。コードをインライン化すると、関数呼び出しのオーバーヘッドは回避されますが、コードが大きくなり、命令キャッシュに悪影響を与えます。

これらのパフォーマンスヒントは、コンパイラによって一般的に無視されることが多くなりました。何も無視しない(またはむしろリンカが無視しない)ことは、inlineと宣言された関数がいくつかのコンパイル単位に現れることがあり、リンカエラーを引き起こすことなく同じ関数の複数のコピーとして扱われるべきです。

関連する問題