なぜ私はこのようなことをする必要があります:
inline double square (double x) { return x*x;}
の代わりに
double square (double x) { return x*x;}
違いはありますか?
前者(inline
を使用)を使用すると、その関数をヘッダーファイルに配置して、複数のソースファイルに含めることができます。 inline
を使用すると、識別子をfile scopeで作成します。これは、static
を宣言するのとよく似ています。 inline
を使用しないと、リンカーから複数のシンボル定義エラーが発生します。
もちろん、これは、関数をコンパイルする必要があるというコンパイラーへのヒントに加えてinlineを使用する場所に(関数呼び出しのオーバーヘッドを回避するために)します。コンパイラは、inline
ヒントに基づいて動作する必要はありません。
はい、違いがあります。 https://isocpp.org/wiki/faq/inline-functions 。
関数がインラインであることを指定すると、コンパイラはメソッドのコードを呼び出される場所に配置します。
void myfunc() {
square(2);
}
と同じです
void myfunc() {
2 * 2;
}
関数を呼び出すとコードがわかりやすくなりますが、その関数が呼び出されると、ローカル状態をスタックにプッシュする必要があり、メソッドに新しいローカル状態が設定され、完了したら以前の状態をポップする必要があります。それは多くのオーバーヘッドです。
最適化レベルを上げると、コンパイラーはループの展開や関数のインライン化などの決定を行います。コンパイラーは、インラインステートメントを無視してもかまいません。
最近のコンパイラでは、おそらくそれほど違いはありません。 inline
なしでインライン化でき、notインライン化できますwithinline
。
ウィキペディアから:インライン関数は、コンパイラーがインライン展開の実行を要求された関数です。言い換えると、プログラマーは、定義された1つの場所で関数を呼び出すコードを生成するのではなく、関数が呼び出されるすべての場所に関数の完全な本体を挿入するようにコンパイラーに要求しました。コンパイラーはこの要求を尊重する義務はありません。
コンパイラーが準拠している場合、インライン関数は、関数が呼び出されていないかのように(呼び出し関数にロジックを配置したかのように)呼び出されたコードにインライン関数を含め、関数呼び出しのオーバーヘッドを回避します。
inline
は、手続き抽象化の概念でうまく機能します。
inline double square (double x) { return x*x;}
int squareTwice(double x) {
double first = square(x);
double second = square(x);
return first * second;
}
上記は、基本的に次のものに似ています。
int squareTwice(double x) {
double first = x*x;
double second = x*x;
return first * second;
}
これは、コンパイラが関数呼び出しをインライン展開すると、関数のコードが呼び出し元のコードストリームに挿入されるためです。したがって、2番目の例を最初の例に手続き的に抽象化する方が簡単かもしれません。
手続きの抽象化により、ルーチンを読みやすい小さなサブルーチンに分割することができます(ただし、これはスタイルの選択になります)。