C++でインライン関数を使用する利点/欠点は何ですか?コンパイラが出力するコードのパフォーマンスを向上させるだけですが、今日の最適化されたコンパイラ、高速CPU、巨大なメモリなど(メモリが不足し、すべてが100KBのメモリに収まらなければならなかった1980 <今日の利点は本当にありますか?
インライン関数は、パラメーターや戻りアドレスなど、スタックのオン/オフをプッシュおよびポップする必要がないため、高速です。ただし、バイナリがわずかに大きくなります。
それは大きな違いをもたらしますか?ほとんどの場合、最新のハードウェアでは十分ではありません。しかし、それは違いを生むことができ、それは一部の人々にとっては十分です。
インラインにマークを付けても、インラインになるという保証はありません。これはコンパイラへの単なる提案です。仮想関数があるときや、再帰が関係しているときなど、不可能な場合があります。また、コンパイラーが使用しないことを選択する場合もあります。
私はこのような状況が検出可能な違いを作っているのを見ることができました:
inline int aplusb_pow2(int a, int b) {
return (a + b)*(a + b) ;
}
for(int a = 0; a < 900000; ++a)
for(int b = 0; b < 900000; ++b)
aplusb_pow2(a, b);
return 42 ;
ステートメントに還元される場合があります。これは私のためにあります 極端なインライン化。実際にはめったに起こりません。コンパイル時間が長くなり、コードが肥大化せず、コードが高速になります。しかし、杯のように、ほとんどの処理をこの方法で解決できないため、どこにでも適用しようとしないでください...それでも、これはとにかくクールです...古風なCおよびC++では、inline
は、register
のようなものです。最適化に関するコンパイラーへの提案(単なる提案にすぎません)。
現代のC++では、inline
は、異なる翻訳単位で複数の定義(宣言ではない)が見つかった場合、それらはすべて同じであり、リンカーは自由に1つを保持し、他のすべてを破棄できることをリンカーに伝えます。
inline
は、ヘッダーファイルに関数が(どれだけ複雑または「線形」に関係なく)定義されている場合に必須であり、リンカーによって「複数定義」エラーが発生することなく複数のソースに含めることができます。
クラス内で定義されたメンバー関数は、テンプレート関数と同様に(グローバル関数とは対照的に)デフォルトで「インライン」です。
//fileA.h
inline void afunc()
{ std::cout << "this is afunc" << std::endl; }
//file1.cpp
#include "fileA.h"
void acall()
{ afunc(); }
//main.cpp
#include "fileA.h"
void acall();
int main()
{
afunc();
acall();
}
//output
this is afunc
this is afunc
FileA.hを2つの.cppファイルに含めることに注意してください。これにより、afunc()
の2つのインスタンスが生成されます。リンカはそれらの1つを破棄します。 inline
が指定されていない場合、リンカはエラーを出します。
インライン化はコンパイラーへの提案であり、自由に無視できます。少量のコードに最適です。
関数がインライン化されている場合、基本的には、実際に別の関数を呼び出すのではなく、関数呼び出しが行われるコードに挿入されます。これにより、実際の通話を行う必要がないため、速度が向上します。
また、CPUがパイプライン処理をサポートするのは、呼び出しによる新しい命令でパイプラインをリロードする必要がないためです。
唯一の欠点は、バイナリサイズが大きくなる可能性があることですが、関数が小さい限り、これはそれほど重要ではありません。
私はこの種の決定を最近コンパイラーに任せる傾向があります(まあ、とにかく賢いものは)。それらを書いた人々は、基礎となるアーキテクチャのはるかに詳細な知識を持っている傾向があります。
インライン関数は、コンパイラーが使用する最適化手法です。関数をインラインにするには、関数プロトタイプにインラインキーワードを追加するだけです。インライン関数は、その関数がコードで使用された場所に関数の完全な本体を挿入するようコンパイラーに指示します。
関数呼び出しのオーバーヘッドは必要ありません。
また、関数呼び出し中にスタックの変数プッシュ/ポップの変数のオーバーヘッドを節約します。
また、関数からの戻り呼び出しのオーバーヘッドも節約されます。
命令キャッシュを利用することにより、参照の局所性を高めます。
インライン化後、コンパイラーは、指定されている場合、プロシージャー内最適化も適用できます。これは最も重要なものです。このように、コンパイラはデッドコードの除去に焦点を当てることができ、分岐予測、誘導変数の除去などにより多くのストレスを与えることができます。
詳細については、このリンクを参照してください http://tajendrasengar.blogspot.com/2010/03/what-is-inline-function-in-cc.html
共有ライブラリを構築する場合、インライン関数が重要であることを付け加えます。関数をインラインでマークしないと、バイナリ形式でライブラリにエクスポートされます。エクスポートされた場合、シンボルテーブルにも表示されます。一方、インライン関数は、ライブラリバイナリにもシンボルテーブルにもエクスポートされません。
ライブラリが実行時にロードされることが意図されている場合、それは重要かもしれません。また、バイナリ互換対応ライブラリにヒットする場合があります。そのような場合、インラインを使用しないでください。
最適化中、多くのコンパイラは、マークを付けていなくても関数をインライン化します。通常、コンパイラーが知らないことを知っている場合にのみ関数をインラインとしてマークする必要があります。これは通常、コンパイラー自体が正しい決定を下すことができるためです。
inline
を使用すると、1つの定義ルールに違反することなく、ヘッダーファイルに関数定義を配置し、そのヘッダーファイルを複数のソースファイルに#include
配置できます。
パフォーマンスがすべてではありません。 C++とCはどちらも組み込みプログラミングに使用され、ハードウェアの上に置かれます。たとえば、割り込みハンドラを記述する場合、追加のレジスタやメモリページをスワップすることなく、コードを一度に実行できることを確認する必要があります。それがインラインが重宝するときです。優れたコンパイラーは、速度が必要なときにいくつかの「インライン化」を行いますが、「インライン」に強制します。
一般的に、最近のコンパイラーが何かをインライン化することを心配している今日では、ほとんど時間の無駄です。コンパイラは、コードの独自の分析とコンパイラに渡される最適化フラグの指定を通じて、実際にこれらすべての考慮事項を最適化する必要があります。速度を気にする場合は、速度を最適化するようコンパイラーに指示してください。スペースを気にする場合は、スペースを最適化するようコンパイラーに指示してください。ほのめかされる別の答えとして、まともなコンパイラは、それが本当に理にかなっている場合、自動的にインライン化さえします。
また、他の人が述べたように、インラインを使用しても何もインラインに保証されません。保証したい場合は、インライン関数ではなくマクロを定義する必要があります。
組み込みを強制するマクロをインライン化および/または定義するタイミング-アプリケーションの全体的なパフォーマンスに影響を与えることが知られているコードの重要なセクションに対して、実証済みで必要な実証済みの速度の向上がある場合のみ。
コンピューターサイエンスの教授は、C++プログラムでインラインを使用しないように勧めました。理由を尋ねられたとき、彼は親切に、最新のコンパイラはインラインをいつ使用するかを自動的に検出するべきだと説明しました。
はい、インラインは可能な限り最適化手法として使用できますが、どうやら関数をインライン化できる場合はいつでも既に行われているようです。
関数をライブラリにインライン化することで同じトラブルに陥ります。インライン関数はライブラリにコンパイルされていないようです。その結果、実行可能ファイルがライブラリのインライン関数を使用したい場合、リンカは「未定義参照」エラーを出力します。 (gcc 4.5を使用してQtソースをコンパイルしました。
デフォルトですべての関数をインラインにしないのはなぜですか?それはエンジニアリングのトレードオフだからです。 「最適化」には少なくとも2つのタイプがあります。プログラムの高速化と、プログラムのサイズ(メモリフットプリント)の削減です。インライン化は一般に速度を上げます。関数呼び出しのオーバーヘッドを取り除き、スタックからパラメーターをプッシュしてプルすることを回避します。ただし、すべての関数呼び出しを関数の完全なコードに置き換える必要があるため、プログラムのメモリフットプリントも大きくなります。事態をさらに複雑にするために、CPUは、超高速アクセスのために、頻繁に使用されるメモリチャンクをCPUのキャッシュに保存することに注意してください。プログラムのメモリイメージを十分に大きくすると、プログラムはキャッシュを効率的に使用できなくなり、最悪の場合、インライン化は実際にプログラムの速度を低下させる可能性があります。コンパイラーはある程度、トレードオフが何であるかを計算でき、ソースコードを見るだけで、あなたができるよりも良い決定を下せるかもしれません。