web-dev-qa-db-ja.com

インラインキーワードとヘッダー定義

関数の前にinlineキーワードを使用することと、ヘッダーで関数全体を宣言することの違いは何ですか?

そう...

int whatever() { return 4; }

vs

.h:

inline int whatever();

.cpp:

inline int myClass::whatever()
{
    return 4;
}

さらに言えば、これは何をするのでしょうか。

inline int whatever() { return 4; }
26
SirYakalot

いくつかの側面があります:

言語

  • 関数がinlineキーワードでマークされている場合、その定義はTUで使用可能であるか、プログラムの形式が正しくありません。
  • クラス定義で正しく定義された関数はすべて、暗黙的にinlineとマークされます。
  • inline(暗黙的または明示的に)とマークされた関数は、(ODRを尊重して)複数のTUで定義できますが、通常の関数の場合はそうではありません。
  • テンプレート関数(完全に特殊化されていない)は、inline関数と同じ扱いを受けます。

コンパイラの動作

  • inlineとマークされた関数は、必要に応じて各オブジェクトファイルで弱い記号として出力されます。これにより、サイズが大きくなる可能性があります(テンプレートの肥大化を調べてください)。
  • コンパイラーは実際に呼び出しをインライン化しますが(つまり、通常の関数呼び出しを実行する代わりに、使用時にコードをコピーして貼り付ける)、完全にコンパイラーの裁量に委ねられます。キーワードの存在は決定に影響を与えるかどうかはわかりませんが、せいぜいヒントです。

リンカーの動作

  • 弱いシンボルは一緒にマージされ、最終的なライブラリで1回出現します。優れたリンカは、複数の定義が一致することを確認できますが、これは必須ではありません。
29
Matthieu M.

なしinlineの場合、複数のシンボルがエクスポートされる可能性があります。関数が名前空間またはグローバルスコープで宣言されている場合(リンカーエラーが発生します)。

ただし、クラスの場合(例に示されているように)、ほとんどのコンパイラーは暗黙的にメソッドをインライン(-fno-default-inlineはGCCでそのデフォルトを無効にします)。

関数をインラインとして宣言すると、コンパイラーはその定義を翻訳で確認することを期待する場合があります。したがって、定義が表示される時間のために予約する必要があります。

より高いレベルで:クラス宣言の定義は、より多くの翻訳で頻繁に表示されます。これにより、最適化が向上し、コンパイル時間が長くなる可能性があります。

手作業による最適化と高速コンパイルの両方が重要でない限り、最近ではクラス宣言でキーワードを使用することは珍しいことです。

10
justin

inlineの目的は、関数を複数の変換単位で定義できるようにすることです。これは、一部のコンパイラーが、使用されている場所にインライン化できるようにするために必要です。テンプレートまたはクラス定義内の関数を定義するときに省略できますが、ヘッダーファイルで関数を定義するときは常に使用する必要があります。

inlineなしでヘッダーに定義するのは非常に悪い考えです。複数の翻訳単位からのヘッダーを含めると、単一定義規則に違反します。コードはおそらくリンクせず、リンクしている場合は未定義の動作を示す可能性があります。

inlineを使用してヘッダーで宣言しますが、ソースファイルで定義することも非常に悪い考えです。定義は、それを使用するすべての翻訳単位で使用可能である必要がありますが、ソースファイルで定義することにより、1つの翻訳単位でのみ使用可能になります。別のソースファイルにヘッダーが含まれていて関数を呼び出そうとすると、プログラムは無効になります。

9
Mike Seymour

この質問は、インライン関数について多くのことを説明しています __ inline__はどういう意味ですか?inlineキーワードについてでしたが)

基本的に、それはヘッダーとは何の関係もありません。ヘッダーで関数全体を宣言すると、関数のソースが含まれているソースファイルが変更されます。インラインキーワードは、結果のコンパイル済み関数が配置される場所を変更します-独自の場所に、すべての呼び出しがそこに行くように、またはすべての呼び出しの代わりに(パフォーマンスのために)行きます。ただし、コンパイラーは、インライン化する関数またはメソッドを選択することがあり、キーワードはコンパイラーにとって単に提案です。インラインで指定されていない関数でも、パフォーマンスが向上する場合は、コンパイラーがインラインになるように選択できます。

3
Cray

複数のオブジェクトを実行可能ファイルにリンクする場合、通常、関数の定義を含むオブジェクトは1つだけである必要があります。 int whatever() { return 4; }の場合-オブジェクトの生成に使用される変換ユニットには、whatever関数の定義(つまり実行可能コード)が含まれます。リンカは、呼び出し元をどちらに転送するかを知りません。 inlineが指定されている場合、実行可能コードは呼び出しサイトにインライン化される場合とされない場合がありますが、そうでない場合、リンカーはすべての定義が同じであると想定し、呼び出し元に任意に1つを選択することができます。に。どういうわけか定義が同じでなかった場合、それはあなたのせいであると考えられ、あなたは未定義の振る舞いをします。 inlineを使用するには、呼び出しをコンパイラーするときに定義を知っている必要があるため、ヘッダーにインライン宣言を配置し、.cppファイルにインライン定義を配置するというアイデアは、すべての呼び出し元が後で発生した場合にのみ機能します。同じ.cppファイル内-一般的には壊れており、(名目上)インライン関数の定義がそれを宣言するヘッダーに表示されることを期待します(または事前の宣言なしに単一の定義があること)。

1
Tony Delroy