inline、__inline、__forceinline
inline 指定子と __inline 指定子は、関数本体のコピーを関数の各呼び出し位置に挿入するようにコンパイラに指示します。
inline function_declarator;
__inline function_declarator; // Microsoft Specific
__forceinline function_declarator; // Microsoft Specific
解説
挿入 (インライン展開またはインライニングと呼ばれます) は、コンパイラの費用対効果分析により利益があるとわかった場合のみ発生します。 インライン展開では、関数呼び出しのオーバーヘッドが軽減されますが、コード サイズが大きくなるという潜在的なコストがあります。
__forceinline キーワードは、費用対効果分析をオーバーライドし、代わりにプログラマの判断に依存します。 __forceinline を使用する場合は注意が必要です。 __forceinline を無制限に使用しても、コードが大きくなり、パフォーマンスはわずかに向上するだけだったり、場合によってはパフォーマンスが低下したりします (たとえば、実行可能ファイルが大きくなってページングが増えるため)。
インライン関数を使用すると、関数呼び出しに関連するオーバーヘッドが回避されるため、プログラムを高速化できます。 インライン展開される関数は、標準の関数では使用できない、コードの最適化の対象になります。
インライン展開に関するオプションとキーワードは、インライン展開の対象となる候補をコンパイラに示すだけです。 関数がインライン展開される保証はありません。 また、__forceinline キーワードでも、特定の関数のインライン展開を強制することはできません。 /clr を指定してコンパイルする場合、関数にセキュリティ属性が適用されていると、コンパイラは関数をインラインにしません。
inline キーワードは C++ だけで使用できます。 __inline キーワードと __forceinline キーワードは、C と C++ の両方で使用できます。 以前のバージョンとの互換性のため、_inline は __inline のシノニムとなっています。
inline キーワードは、インライン展開が優先されることをコンパイラに指示します。 ただし、コンパイラは、コードをインラインで挿入する代わりに、関数の別のインスタンスを作成 (インスタンス化) し、標準の呼び出しリンケージを作成できます。 このようになるのは、次の 2 つの場合です。
再帰関数。
翻訳単位の別の場所にあるポインターを通じて参照される関数。
これらの理由は、他の要因と共に、インライン展開に関するコンパイラの判断に影響する可能性があります。関数のインライン展開を inline 指定子で確実に行うことはできません。
通常の関数の場合と同様に、インライン関数への引数の評価の順序は定義されていません。 実際には、通常の関数呼び出しプロトコルで渡される引数の評価順序とは異なる場合があります。
/Ob コンパイラ最適化オプションは、関数のインライン展開が実際に発生するかどうかの確認に役立ちます。
/LTCG は、ソース コードで要求されたかどうかに関係なく、モジュール間のインライン展開を実行します。
例 1
// inline_keyword1.cpp
// compile with: /c
inline int max( int a , int b ) {
if( a > b )
return a;
return b;
}
クラスのメンバー関数は、inline キーワードを使用するか、クラス定義内に関数定義を配置することにより、インラインとして宣言できます。
例 2
// inline_keyword2.cpp
// compile with: /EHsc /c
#include <iostream>
using namespace std;
class MyClass {
public:
void print() { cout << i << ' '; } // Implicitly inline
private:
int i;
};
Microsoft 固有の仕様 →
__inline キーワードは、inline に相当します。
__forceinline でも、コンパイラはすべての状況でコードをインライン展開することはできません。 次の場合、コンパイラは関数をインライン展開できません。
関数またはその呼び出し元が /Ob0 (デバッグ ビルドの既定オプション) でコンパイルされる。
関数と呼び出し元が、異なる種類の例外処理を使用する (一方は C++ 例外処理、他方は構造化例外処理)。
関数に可変個引数リストが含まれている。
関数が /Og、/Ox、/O1、または /O2 を指定してコンパイルされていない場合に、インライン アセンブリを使用する。
関数が再帰的で、#pragma inline_recursion(on) を伴わない。 プラグマによって、再帰関数はインライン展開され、既定の深さは 16 呼び出しになります。 インラインの深度を減らすには、inline_depth プラグマを使用します。
関数が仮想で、仮想的に呼び出される。 仮想関数への直接呼び出しはインライン展開できます。
プログラムが関数のアドレスを受け取り、関数へのポインターによって呼び出される。 受け取られるアドレスを持っている関数への直接呼び出しはインライン展開できます。
関数が naked __declspec 修飾子でもマークされている。
__forceinline で宣言された関数をコンパイラがインライン展開できない場合、レベル 1 の警告が生成されます。
再帰関数は、inline_depth プラグマによって指定される深度 (最大で 16 の呼び出し) までインラインで置き換えることができます。 その深さの後、再帰関数の呼び出しは、関数のインスタンスへの呼び出しとして扱われます。 再帰関数がインライン ヒューリスティックによってチェックされる深さは、16 を超えることはできません。 inline_recursion プラグマは、現在展開中の関数のインライン展開を制御します。 関連情報については、インライン関数の展開 (/Ob) コンパイラ オプションの説明を参照してください。
END Microsoft 固有の仕様
inline 指定子の使い方の詳細については、以下を参照してください。