回答:
inline
Cからです; C ++の新機能ではありません。
プログラマがコードの最適化を支援できるように設計されたCキーワード(register
およびinline
)があります。コンパイラーはレジスターの割り当てと関数をインライン化するタイミングの決定をよりうまく行えるため、これらは現在一般的に無視されています(実際、コンパイラーは関数を異なる時間にインライン化することもインライン化しないこともできます)。最新のプロセッサでのコード生成は、リッチーがCを発明したときに一般的なより決定論的なものよりもはるかに複雑です。
C ++では、この言葉の意味は、複数の同一の定義を持つことができ、それを使用するすべての翻訳単位で定義する必要があるということです。(つまり、インライン化できることを確認する必要があります。)inline
問題なくヘッダーに関数を含めることができ、クラス定義で定義されたメンバー関数は自動的に効果的になりinline
ます。
inline
。
inline
最初にC ++で標準化されたと確信していますが、すでにCのベンダー拡張として利用可能でした。
inline
、C99以降の規則inline
はC ++の規則とは異なることに注意してください。
もともとinline
は、関数の呼び出しをインライン化する必要があるという非常に強力なヒントでした。
ただし、保証される唯一の効果はinline
、関数を複数の翻訳単位で(事実上同一に)定義できるようにすることです。たとえば、ヘッダーファイルに定義を配置します。
現在、一部のコンパイラーはインライン化のヒントに従っています(g ++など)。また、Visual C ++など、一部のコンパイラはそれほど重要視していません。しかし、すべてが保証に従う必要があります。
最適化のヒントとリンカレベルの破棄可能な定義と呼ばれるこれらの2つの意味が同じキーワードに存在するのは残念です。これは、一方が他方なしでは実質的に存在できないことを意味するためです。
残念なことにinline
(または、破棄可能な定義に関する別のキーワード)¹をデータに適用できないことも残念です。
ヘッダーのみのモジュールが普及するにつれて、リンカレベルの破棄可能なデータの必要性が高まっています。たとえば、多くのBoostサブライブラリはヘッダーのみです。
ただし、データについては、テンプレートを使用してちょっとしたトリックを適用できます。クラステンプレートで定義し、typedef
テンプレートパラメータvoid
(または何でも)を提供します。これは、One Definition Ruleがテンプレートに対して特定の例外を作成するためです。
注:
¹ inline
変数はC ++ 17でサポートされます。
inline
。
デフォルトですべての関数をインラインにしないのはなぜですか?それはエンジニアリングのトレードオフだからです。「最適化」には、少なくとも2つのタイプがあります。プログラムの高速化と、プログラムのサイズ(メモリフットプリント)の削減です。インライン化は一般に速度を上げます。関数呼び出しのオーバーヘッドを取り除き、スタックからパラメーターをプッシュしてプルすることを回避します。ただし、すべての関数呼び出しを関数の完全なコードに置き換える必要があるため、プログラムのメモリフットプリントも大きくなります。事態をさらに複雑にするために、CPUは頻繁に使用されるメモリチャンクをCPUのキャッシュに保存して、超高速アクセスを実現します。プログラムのメモリイメージを十分に大きくすると、プログラムはキャッシュを効率的に使用できなくなり、最悪の場合、インライン化は実際にプログラムの速度を低下させる可能性があります。
「インライン」を理解するには、歴史と20年前(および30年前)の生活を理解する必要があります。
メモリがほとんどないコンピューターでコードを書いていたため、コンパイラーがプログラムを構成するすべてのコードを一度に処理することはできませんでした。コンパイラも非常に遅かったので、変更されていないコードを再コンパイルする必要はありませんでした(すべてのコードを再コンパイルするのに24時間以上かかりました)取り組んだ。
そのため、各コードファイルは個別にオブジェクトファイルにコンパイルされました。各オブジェクトファイルは、含まれるすべての関数のリストと、関数の「アドレス」で始まりました。オブジェクトファイルには、呼び出しの場所とともに、他のオブジェクトファイルで呼び出されたすべての関数のリストも含まれていました。
リンカは、最初にすべてのオブジェクトファイルを読み、そして彼らは、アドレスにしていたファイルと一緒に、彼らはエクスポートされたすべての関数のリストを、構築でしょう。次に、すべてのオブジェクトファイルを再読み込みしてプログラムファイルに出力し、すべての「外部」関数呼び出しを関数のアドレスで更新します。
リンカは、外部関数呼び出しへの参照を修正する以外の方法で、コンパイラによって生成されたマシンコードを変更または最適化しませんでした。 リンカはオペレーティングシステムの一部であり、ほとんどのコンパイラより前のものでした。人々が新しいコンパイラを書いたとき、現在のリンカで動作し、現在のオブジェクトファイルにリンクできるようにする必要がありました。
コンパイラは、コンパイルされた「.c」または「.cpp」ファイル内のコードと、含まれているすべてのヘッダーファイルのみを見ました。そのため、他の「.c」または「.cpp」ファイルのコードに基づいて最適化を行うことはできませんでした。
「インライン」キーワードを使用すると、関数(メソッド)の本文をヘッダーファイルで定義できるため、コンパイラは関数を呼び出すコードをコンパイルしながら関数のコードを使用できます。たとえば、別の.cppファイルで定義されたコレクションクラスがある場合、このクラスには1行のコードが含まれる「isEmpty」メソッドがあり、関数の呼び出しの代わりに結果のプログラムが大幅に高速化されます、関数呼び出しはこの1行に置き換えられました。
当時、「インライン」キーワードは、多くのプログラマーがオブジェクトのプライベートフィールドにアクセスするだけで、関数呼び出しのコストを回避しながらデータのカプセル化を可能にする「安くて簡単な」方法と見なされていました。 (はるかに悪い方法でコードを「インライン化」するマクロは、当時一般的でした。)
最近の「リンカー」は多くのコード最適化を行い、コンパイラとしていくつかのチームによって作成される傾向があります。コンパイラは、多くの場合、コードが正しいことを確認して「圧縮」するだけで、マシンコード作成のほとんどのタスクはリンカーに任せます。
標準の内容を見てみましょう(太字で強調されている重要な部分):
2.インライン指定子を使用した関数宣言は、インライン関数を宣言します。インライン指定子は、呼び出しポイントでの関数本体のインライン置換が通常の関数呼び出しメカニズムより優先されることを実装に示します。呼び出しポイントでこのインライン置換を実行するための実装は必要ありません。ただし、このインライン置換が省略された場合でも、インライン関数の他のルールは引き続き尊重されます。
— C ++標準、ISO / IEC 14882: 2003、7.1.2関数指定子[dcl.fct.spec]
そのため、確認したい場合は、コンパイラのドキュメントを読む必要があります。
すべてをインライン化することは、多くの重複したマシンコードをもたらす可能性があるため、悪い考えです...
だからあなたは知っておく必要があります:
簡単な答えはありません。最適なものを見るには、それをいじる必要があります。「関数を使用しない」、「関数を常に使用する」、「関数がコードのN行未満の場合にのみ関数を使用する」などの単純な答えには妥協しないでください。これらの万能のルールは簡単に書き留めることができますが、次善の結果をもたらします。
inline
inline
inline
— C ++ FAQ、インライン関数、9.3
inline
関数はパフォーマンスを改善しますか?
inline
OPが一部を見逃しているように見えるので、知識を繰り返してポイントを伝えています。それが彼がポイントを獲得できない中核的な理由です。1 ...彼はそのポイントの下に何があるかを理解している必要がポイントを得るためには
インラインキーワードを使用する正当な理由を説明します。
チケットプリンターまたは同様の小規模システムなどの組み込みシステム。プロセッサは非常に制限されており、関数呼び出し(スタック上の関数パラメーターの準備、呼び出し、スタックからのパラメーターのフェッチ、応答の返送など)の実行には、関数自体のほかに数ミリ秒かかります。
呼び出し時間が約60ミリ秒(実際の関数ではなく呼び出しのためだけ)で、50回の反復(ツリー内のループ呼び出しまたは反復呼び出し)があるとします。
その関数呼び出しから前後に移動する時間は60 * 50 = 3000(3秒)かかります。
メモリがある場合は、間違いなくインラインで3秒節約できます。
したがって、インラインは、実行速度が必要な場合に基本的に使用されます。私が関わったいくつかのプロジェクトでは、呼び出し時間は実行時間よりも長く、インラインを使用する典型的な状況でした。