3

インライン関数についてのドキュメントを読んだことがあります。私のドキュメントによると、インライン関数には2つのタイプがあります:implicity functionexplicity function

Explicity functioninline関数の前にキーワードを使用し、クラスの外部で使用します。例えば:

inline int Math::add(int a, int b){ return a + b; }

Implicity function:クラス内のすべてのメソッドは暗黙的です。例えば:

class Math {
   int add(int a, int b) { return a + b;}   // implicity inline function
};

だから、もしこれが本当なら、私が使いたくないすべてのメソッドinlineは、クラスの外で宣言しなければなりませんよね?そして、これが本当なら、クラス内にメソッドを実装でき、インライン関数は必要ありません。

ありがとう :)

4

4 に答える 4

7

インラインでないことを保証する唯一の方法は、コンパイル時に到達不能にすることです。たとえば、本文の定義をヘッダーではなくcppファイルに入れます。

更新:コメント提供者は、関数本体を別のコンパイル単位に配置しても、役立つとは限らないと述べています。彼は絶対に正しい。通常は役に立ちますが、コンパイラによっては関数をインライン化する場合があります。したがって、コンパイラに依存しないインライン化を無効にする信頼できる方法はありません。

すべてのインライン化は、最適化の問題にすぎません。適切な最適化がオンになっている場合は、インラインキーワードを記述することで、関数をインライン化することをお勧めすることをコンパイラーに通知するだけです。コンパイラーに関数をインライン化させることも、コンパイラーに関数をインライン化しないように強制することもできません。VC ++などの特定のコンパイラーには、そうする方法があります(__declspec(noinline))が、それらはすべてコンパイラーに依存します。

そして、なぜインライン化を無効にする必要があるのですか?多くの場合、コンパイラはよく知っています...デバッグ目的の場合は、最適化を無効にするか、少なくとも関数のインライン化を無効にします。プラグマを使用して、単一のファイルでこれを行うこともできます。とにかく、リリースバージョンのデバッグは通常回避する必要がありますが、もちろん回避できない場合もあります。

于 2012-11-14T08:48:19.313 に答える
5

C ++標準から読み、「暗黙のインライン関数」がどのように定義されているか:

メンバー関数は、クラス定義で定義(8.4)できます。この場合、インラインメンバー関数(7.1.2)であるか、すでに宣言されているがクラス定義で定義されていない場合は、クラス定義の外部で定義できます。クラス定義。クラス定義の外部に表示されるメンバー関数定義は、クラス定義を囲む名前空間スコープに表示されるものとします。クラス定義の外に現れるメンバー関数定義を除いて、またクラステンプレートのメンバー関数の明示的な特殊化とクラス定義の外に現れるメンバー関数テンプレート(14.7)を除いて、メンバー関数は再宣言されないものとします。

また、コンパイラは、実際に置換が実行されることを保証しません。

インライン指定子を使用した関数宣言(8.3.5、9.3、11.4)は、インライン関数を宣言します。インライン指定子は、呼び出しポイントでの関数本体のインライン置換が通常の関数呼び出しメカニズムよりも優先されることを実装に示します。 呼び出しの時点でこのインライン置換を実行するために実装は必要ありません。ただし、このインライン置換が省略されている場合でも、7.1.2で定義されているインライン関数の他の規則は尊重されます。

他のすべての関数はおそらく「非インライン」になりますが、最適化をオンにすると、多くの奇妙なことが起こる可能性があります。たとえば、gcc-最適化オプションを見てください。

  • -finline-small-functions の一部としてO2

    本体が予想される関数呼び出しコードよりも小さい場合は、関数を呼び出し元に統合します(したがって、プログラムの全体的なサイズが小さくなります)。コンパイラーは、この方法で統合する価値があるほど単純な関数をヒューリスティックに決定します。このインライン化は、インラインで宣言されていない関数も含め、すべての関数に適用されます。

  • -finline-functions の一部としてO3

    インラインとして宣言されていない場合でも、インライン化するためのすべての関数を検討してください。コンパイラーは、この方法で統合する価値のある関数をヒューリスティックに決定します。
    特定の関数へのすべての呼び出しが統合され、関数が静的であると宣言されている場合、関数は通常、それ自体でアセンブラーコードとして出力されません。

  • -finline-functions-called-once の一部としてO1

    インラインとしてマークされていない場合でも、呼び出し元にインライン化するために一度呼び出されるすべての静的関数を検討してください。特定の関数の呼び出しが統合されている場合、その関数はそれ自体でアセンブラーコードとして出力されません。

一方、コンパイラにインライン関数(-fno-inline)を使用しないように指示することもできます。

always_inline属性でマークされた関数以外の関数をインライン展開しないでください。これは、最適化しない場合のデフォルトです。
単一の関数は、noinline属性でマークすることにより、インライン化を免除できます。

于 2012-11-14T08:58:07.493 に答える
3

はい、それは本当です。クラス定義内で定義されたすべてのメソッド暗黙的にinlineです。

inlineコンパイラが実際にコードにインライン化するという意味ではないことに注意してください。インラインにしたくない場合は、実装ファイルで実装を分離するだけです。

于 2012-11-14T08:38:38.960 に答える
2

まず、inlineクラス内で定義された関数にキーワードを使用することは完全に合法です。

struct MyClass
{
    inline int someFunctions() { return 42; }
};

ここでのキーワードは冗長ですが、違法ではありません。

次に、inlineキーワードはコンパイラへのヒントとなることを目的としていますが、1つの定義規則に違反することで未定義の動作を引き起こすことなく、関数の複数の定義を許可することが唯一の正式な必須の意味です。また、コンパイラは場合によってはそれを無視します。

  • ほとんどのコンパイラは、デバッグ用に設計されたオプションが指定されている場合(または最適化がオフになっている場合)にそれを無視し、実際には何もインライン化しません。

  • 最大最適化がオンになっている場合、最高のコンパイラはそれを完全に無視します。関数がインライン化されるかどうかは、コードとプロファイリングデータのコンパイラーの分析に一意に依存し、特定の関数は、別の場所ではなく、ある場所(タイトループの真ん中にある場所)にインライン化されます。(そして、他のポスターが言っていることとは異なり、これは、呼び出しサイトと関数定義が2つの異なる変換単位にある場合でも発生します。)

これら2つの極端な状況の間では、多くのコンパイラーはモジュール間分析を行わ、少なくともある程度の最適化がオンになっている場合、少なくともほとんどの場合、「ヒントを得る」でしょう。 たとえば、コンパイラがコンパイル時に再帰の深さを判別できない場合、再帰インライン関数はほぼ確実にインラインで生成されません。また、ほとんどのコンパイラは、ローカライズされた静的分析でオブジェクトの実際のタイプを判別できない場合、仮想関数をインラインで生成できませんが、特定のオーバーロードが99%の確率で呼び出されることを示す、特定のプロファイラー出力の一部が最適です。 、を生成しif、その1つのケースをインライン化する場合があります。

一般に、ヘッダーファイルでの定義はできるだけ少なくする必要があるため、「エクスポートされた」クラスのinline場合、プロファイラーが絶対に必要であると言わない限り、(明示的または暗黙的に)使用しません。ソースファイルで定義されているローカルクラスの場合、クラス定義で関数を定義するかどうかはスタイルの問題です(そして、コンパイラがそれらをインライン化するかどうかについては、違いが生じる場合とそうでない場合があります。通常のデバッグオプションでは、ほとんどのコンパイラは何もインライン化しません)。

于 2012-11-14T10:01:32.577 に答える