1、inline キーワードを導入した理由
c/c++ では、頻繁に呼び出される小さな関数がスタック領域(スタックメモリ)を大量に消費する問題を解決するために、特別に導入されたのがinline修飾子で、インライン関数を表します。
スタック領域とは、プログラムのローカルデータ(つまり関数内のデータ)を置くメモリ領域のことです。
システムでは、スタック領域は有限です。頻繁かつ大量に使用すると、スタック領域の不足によりプログラムエラーが発生する問題を引き起こします。例えば、関数の無限ループ再帰呼び出しの最終結果は、スタックメモリ空間の枯渇を招きます。
以下に例を見てみましょう:
例
上記の例は標準的なインライン関数の使い方です。inline修飾を使用することによる利点は表面的にはわかりませんが、実際には内部で、各forループの内部でのすべての呼び出しdbtest(i)箇所が次のように置き換えられます。(i%2>0)?"奇":"偶"これにより、関数を頻繁に呼び出してスタックメモリの領域を繰り返し確保することによる消費を回避できます。
2、inline の使用制限
inlineinline の使用には制限があります。inline は関数本体内のコードが単純な関数にのみ適しており、while、switch などの複雑な構造制御文を含めることはできません。また、インライン関数自体は直接再帰関数であってはなりません(つまり、自分自身の内部で自分自身を呼び出す関数)。
3、inline はコンパイラへの単なる提案である
inlineinline 関数は単にコンパイラへの提案であり、最終的に本当にインライン化されるかどうかはコンパイラ次第です。コンパイラが関数は複雑ではなく呼び出し地点で展開できると判断すれば、実際にインライン化されます。インラインと宣言したからといってインライン化されるわけではなく、インラインの宣言は単なる提案に過ぎません。
4、inline 関数の定義はヘッダーファイルに置くことを推奨
次に、インライン関数は呼び出し地点で展開されなければならないため、コンパイラはインライン関数の定義をどこでも見ることができなければなりません。そうでなければ、非インライン関数の呼び出しになってしまいます。したがって、インライン関数を呼び出す各ファイルにそのインライン関数の定義。
が現れている必要があります。したがって、インライン関数の定義を置くのはヘッダーファイルに実装するのが適切であり、ファイルごとに一度実装する手間を省けます。
宣言と定義は一致させる必要があります。:各ファイルでこのインライン関数を一度ずつ実装する場合、各定義が同じであることを保証するのが最善です。そうでなければ、未定義の動作を引き起こします。各ファイルの定義が同じでない場合、コンパイラがどれを展開するかは特定のコンパイラ次第です。したがって、インライン関数の定義を置くのがヘッダーファイルに最善です。
5、クラスのメンバー関数と inline
定義クラス内のメンバー関数はデフォルトですべてインラインです。クラス定義時に関数定義をクラス内で行えば、もちろん最善です。クラス内でメンバー関数の定義を行わず、その関数をインライン化したい場合は、クラス外でinlineinline を付ける必要があり、そうでなければインラインとは見なされません。
メンバー関数の定義本体をクラス宣言内に置くと記述の便宜は図れますが、良いプログラミングスタイルとは言えません。上記の例は次のように変更すべきです:
6、inline は「実装のためのキーワード」である
inline キーワードinlineは関数定義本体と一緒に置くことで初めて関数をインラインにでき、単にinlineを関数宣言の前に置くだけでは何の効果もありません。
次のようなスタイルの関数はFooインライン関数にはなれません:
inline void Foo(int x, int y); // inline 仅与函数声明放在一起
void Foo(int x, int y){}
一方、次のようなスタイルの関数はFooインライン関数になります:
void Foo(int x, int y);
inline void Foo(int x, int y) {} // inline 与函数定义体放在一起
つまり、inline は「実装のためのキーワード」であり、「宣言のためのキーワード」ではありません。一般的に、ユーザーは関数の宣言を読むことはできますが、関数の定義を見ることはできません。ほとんどの教科書ではインライン関数の宣言と定義本体の前に inline キーワードを付けていますが、私はinline は関数の宣言に現れるべきではないと思います。この詳細は関数の機能には影響しませんが、高品質な C++/C プログラム設計スタイルの基本原則を示しています:宣言と定義は混同すべきではなく、ユーザーは関数がインライン化を必要とするかどうかを知る必要も、知るべきでもありません。
7、inline の使用は慎重に
インラインは関数の実行効率を向上させることができるのに、なぜすべての関数をインライン関数として定義しないのでしょうか?すべての関数がインライン関数なら、「インライン」というキーワードはまだ必要でしょうか?
インライン化はコードの膨張(複製)を代償として、単に関数呼び出しのオーバーヘッドを省き、関数の実行効率を向上させます。
関数本体内のコードを実行する時間が関数呼び出しのオーバーヘッドに比べて大きい場合、効率の向上はほとんど得られません。一方、インライン関数の呼び出し箇所ごとにコードを複製するため、プログラムの総コード量が増加し、より多くのメモリ領域を消費します。
以下の場合はインラインを使用すべきではありません:
(1)関数本体内のコードが比較的長い場合、インラインを使用するとメモリ消費のコストが高くなります。。
(2)関数本体内にループが現れる場合、関数本体内のコードを実行する時間は関数呼び出しのオーバーヘッドよりも大きくなります。クラスのコンストラクタとデストラクタは、インラインを使用する方が効果的だと誤解されがちです。注意してください。コンストラクタとデストラクタはいくつかの動作を隠している可能性があります。、例えば「こっそりと」基底クラスやメンバーオブジェクトのコンストラクタとデストラクタを実行している場合があります。したがって、コンストラクタとデストラクタの定義本体をむやみにクラス宣言内に置かないでください。優れたコンパイラは関数の定義本体に基づいて、価値のないインライン化を自動的に取り止めます(これは inline が関数の宣言に現れるべきではないことをさらに示しています)。
8、まとめ
インライン関数は性能を向上させる万能薬ではありません。関数が非常に短い場合にのみ望ましい効果が得られます。しかし、関数がそれほど短くなく、多くの場所で呼び出される場合、実行可能ファイルのサイズが大きくなります。
最も悩ましいのはやはりコンパイラがインライン化を拒否するときです。古い実装では結果はあまり満足のいくものではありませんでしたが、新しい実装では大きく改善されていますが、それでも完全ではありません。一部のコンパイラはどの関数がインライン化できるかできないかを指摘できるほど賢いものもありますが、ほとんどのコンパイラはそれほど賢くないため、私たちの経験による判断が必要です。インライン関数が性能を向上させないのであれば、使用を避けてください!
原文リンク:https://www.cnblogs.com/fnlingnzb-learner/p/6423917.html