C ++のインライン関数。ポイントは何ですか?


19

私が読んだことによると、コンパイラーはインライン関数の関数呼び出しをその本体で置き換える義務はありませんが、可能であれば置き換えます。これは私に考えさせられました-それが事実である場合、なぜ私たちはインラインワードを持っていますか?デフォルトですべての関数をインライン関数にして、呼び出しを関数本体で置き換えることができるかどうかをコンパイラーに判断させてみませんか?


1
こちら。ページ6
EpsilonVector

回答:


40

inlineCからです; C ++の新機能ではありません。

プログラマがコードの最適化を支援できるように設計されたCキーワード(registerおよびinline)があります。コンパイラーはレジスターの割り当てと関数をインライン化するタイミングの決定をよりうまく行えるため、これらは現在一般的に無視されています(実際、コンパイラーは関数を異なる時間にインライン化することもインライン化しないこともできます)。最新のプロセッサでのコード生成は、リッチーがCを発明したときに一般的なより決定論的なものよりもはるかに複雑です。

C ++では、この言葉の意味は、複数の同一の定義を持つことができ、それを使用するすべての翻訳単位で定義する必要があるということです。(つまり、インライン化できることを確認する必要があります。)inline問題なくヘッダーに関数を含めることができ、クラス定義で定義されたメンバー関数は自動的に効果的になりinlineます。


3
+1の履歴inline
タマラウィスマン

11
これはinline最初にC ++で標準化されたと確信していますが、すでにCのベンダー拡張として利用可能でした。
ベンフォークト

@Ben Voigt:そのとおりです。私が最初にC.でそれに遭遇しました
デビッド・ソーンリー

5
また、履歴が間違っているだけでなくinline、C99以降の規則inlineはC ++の規則とは異なることに注意してください。
アルフP.シュタインバッハ14

27

もともとinlineは、関数の呼び出しをインライン化する必要があるという非常に強力なヒントでした。

ただし、保証される唯一の効果はinline、関数を複数の翻訳単位で(事実上同一に)定義できるようにすることです。たとえば、ヘッダーファイルに定義を配置します。

現在、一部のコンパイラーはインライン化のヒントに従っています(g ++など)。また、Visual C ++など、一部のコンパイラはそれほど重要視していません。しかし、すべてが保証に従う必要があります。

最適化のヒントとリンカレベルの破棄可能な定義と呼ばれるこれらの2つの意味が同じキーワードに存在するのは残念です。これは、一方が他方なしでは実質的に存在できないことを意味するためです。

残念なことにinline(または、破棄可能な定義に関する別のキーワード)¹をデータに適用できないことも残念です。

ヘッダーのみのモジュールが普及するにつれて、リンカレベルの破棄可能なデータの必要性が高まっています。たとえば、多くのBoostサブライブラリはヘッダーのみです。

ただし、データについては、テンプレートを使用してちょっとしたトリックを適用できます。クラステンプレートで定義し、typedefテンプレートパラメータvoid(または何でも)を提供します。これは、One Definition Ruleがテンプレートに対して特定の例外を作成するためです。

注:
¹ inline変数はC ++ 17でサポートされます。


1
+1に関する追加情報については+1 inline
タマラウィスマン

1
非常にひどく設計されたC ++言語は、通常は有能で注意深いプログラマーに、静的オブジェクトを使用する合理的だが正式には未定義のコードを書かせようとするため、「実質的に同一」は実際には非常に注意が必要な条件です。
curiousguy

6

デフォルトですべての関数をインラインにしないのはなぜですか?それはエンジニアリングのトレードオフだからです。「最適化」には、少なくとも2つのタイプがあります。プログラムの高速化と、プログラムのサイズ(メモリフットプリント)の削減です。インライン化は一般に速度を上げます。関数呼び出しのオーバーヘッドを取り除き、スタックからパラメーターをプッシュしてプルすることを回避します。ただし、すべての関数呼び出しを関数の完全なコードに置き換える必要があるため、プログラムのメモリフットプリントも大きくなります。事態をさらに複雑にするために、CPUは頻繁に使用されるメモリチャンクをCPUのキャッシュに保存して、超高速アクセスを実現します。プログラムのメモリイメージを十分に大きくすると、プログラムはキャッシュを効率的に使用できなくなり、最悪の場合、インライン化は実際にプログラムの速度を低下させる可能性があります。


5
しかし、コンパイラーは、一般的なプログラマーよりもはるかにこのことを理解できます(実際に!)。したがって、これは有効な引数ではありません。
コンラッドルドルフ

すべての関数呼び出しは、関数の完全なコードで置き換える必要があります」そして、インライン関数は、呼び出しシーケンスが省略され、関数のアセンブリコードが所定の場所にコピーされる関数ではありません。インライン関数は、高レベルの中間コードをインラインにすることにより、適切にコンパイルされます。これにより、コンパイラーは関数本体をクリーンマクロ(Cプリプロセッサーマクロの癖のないマクロ)として効果的に処理し、潜在的に多くの最適化を利用できます。
-curiousguy

3

「インライン」を理解するには、歴史と20年前(および30年前)の生活理解する必要があります

メモリがほとんどないコンピューターでコードを書いていたため、コンパイラーがプログラムを構成するすべてのコードを一度に処理することはできませんでした。コンパイラも非常に遅かったので、変更されていないコードを再コンパイルする必要はありませんでした(すべてのコードを再コンパイルするのに24時間以上かかりました)取り組んだ。

そのため、各コードファイルは個別にオブジェクトファイルにコンパイルされました。各オブジェクトファイルは、含まれるすべての関数のリストと、関数の「アドレス」で始まりました。オブジェクトファイルには、呼び出しの場所とともに、他のオブジェクトファイルで呼び出されたすべての関数のリストも含まれていました。

リンカは、最初にすべてのオブジェクトファイルを読み、そして彼らは、アドレスにしていたファイルと一緒に、彼らはエクスポートされたすべての関数のリストを、構築でしょう。次に、すべてのオブジェクトファイルを再読み込みしてプログラムファイルに出力し、すべての「外部」関数呼び出しを関数のアドレスで更新します。

リンカは、外部関数呼び出しへの参照を修正する以外の方法で、コンパイラによって生成されたマシンコードを変更または最適化しませんでした。 リンカはオペレーティングシステムの一部であり、ほとんどのコンパイラより前のものでした。人々が新しいコンパイラを書いたとき、現在のリンカで動作し、現在のオブジェクトファイルにリンクできるようにする必要がありました。

コンパイラは、コンパイルされた「.c」または「.cpp」ファイル内のコードと、含まれているすべてのヘッダーファイルのみを見ました。そのため、他の「.c」または「.cpp」ファイルのコードに基づいて最適化を行うことはできませんでした。

「インライン」キーワードを使用すると、関数(メソッド)の本文をヘッダーファイルで定義できるため、コンパイラは関数を呼び出すコードをコンパイルしながら関数のコードを使用できます。たとえば、別の.cppファイルで定義されたコレクションクラスがある場合、このクラスには1行のコードが含まれる「isEmpty」メソッドがあり、関数の呼び出しの代わりに結果のプログラムが大幅に高速化されます、関数呼び出しはこの1行に置き換えられました。

当時、「インライン」キーワードは、多くのプログラマーがオブジェクトのプライベートフィールドにアクセスするだけで、関数呼び出しのコストを回避しながらデータのカプセル化を可能にする「安くて簡単な」方法と見なされていました。 (はるかに悪い方法でコードを「インライン化」するマクロは、当時一般的でした。)

最近の「リンカー」は多くのコード最適化を行い、コンパイラとしていくつかのチームによって作成される傾向があります。コンパイラは、多くの場合、コードが正しいことを確認して「圧縮」するだけで、マシンコード作成のほとんどのタスクはリンカーに任せます。


2

標準の内容を見てみましょう(太字で強調されている重要な部分):

2.インライン指定子を使用した関数宣言は、インライン関数を宣言します。インライン指定子は、呼び出しポイントでの関数本体のインライン置換が通常の関数呼び出しメカニズムより優先されることを実装に示します。呼び出しポイントでこのインライン置換を実行するための実装は必要ありません。ただし、このインライン置換が省略された場合でも、インライン関数の他のルールは引き続き尊重されます。

C ++標準、ISO / IEC 14882: 2003、7.1.2関数指定子[dcl.fct.spec]

そのため、確認したい場合は、コンパイラのドキュメントを読む必要があります。

すべてをインライン化することは、多くの重複したマシンコードをもたらす可能性があるため、悪い考えです...

だからあなたは知っておく必要があります:

簡単な答えはありません。最適なものを見るには、それをいじる必要があります。「関数を使用しない」、「関数を常に使用する」、「関数がコードのN行未満の場合にのみ関数を使用する」などの単純な答えには妥協しないでください。これらの万能のルールは簡単に書き留めることができますが、次善の結果をもたらします。inlineinlineinline

C ++ FAQ、インライン関数、9.3 inline関数はパフォーマンスを改善しますか?


1
あなたの言うことは本当ですが、プログラマーとしてインライン化するかどうかのあなたの決定ではないので、関連がありません。キーワードを入力すると、関数がインライン化される場合とされない場合があります。キーワードを入力しなくても、インライン化される場合とされない場合があります。あなたがキーワードを置くとき、コンパイラが実際に決定を下すものであるということについて、どんなルールを持っているのも無意味です。
ケイトグレゴリー

それはあなたとまったく同じだと言ったらどうでしょうか?簡単な答えはありません
タマラWijsman

OPの質問に答えないため、関係ありません。彼は「インラインは何をするのか」を求めているのではなく、「whats the point」を求めているのです。そして、あなたの答えは、私たち全員がインラインについてすでに知っていることを繰り返しているだけです。
DavorŽdralo

@Davor:「ポイントは何ですか?」FAQに準拠していないため、質問内の質問に回答しています。inlineOPが一部を見逃しているように見えるので、知識を繰り返してポイントを伝えています。それが彼がポイントを獲得できない中核的な理由です。1 ...彼はそのポイントの下に何があるかを理解している必要がポイントを得るためには
タマラWijsman

なぜ地獄はFAQに準拠しないのでしょうか?標準では、インラインキーワードの構文とセマンティクスが説明されています。OPの質問は、目的は何ですか、いつ使用する必要があるか、どの問題を解決する必要があるのでしょうか。FAQに準拠していないことがわかりません。
デイヴァーオドラロ

1

インラインキーワードを使用する正当な理由を説明します。

チケットプリンターまたは同様の小規模システムなどの組み込みシステム。プロセッサは非常に制限されており、関数呼び出し(スタック上の関数パラメーターの準備、呼び出し、スタックからのパラメーターのフェッチ、応答の返送など)の実行には、関数自体のほかに数ミリ秒かかります。

呼び出し時間が約60ミリ秒(実際の関数ではなく呼び出しのためだけ)で、50回の反復(ツリー内のループ呼び出しまたは反復呼び出し)があるとします。

その関数呼び出しから前後に移動する時間は60 * 50 = 3000(3秒)かかります。

メモリがある場合は、間違いなくインラインで3秒節約できます。

したがって、インラインは、実行速度が必要な場合に基本的に使用されます。私が関わったいくつかのプロジェクトでは、呼び出し時間は実行時間よりも長く、インラインを使用する典型的な状況でした。


え、何?コードにインラインを配置することは、コンパイラが実際にインライン化することを意味するものではなく、そこに配置しないことは、コードがインライン化しないという意味ではありません。これは単なるヒントであり、今日のコンパイラではほとんど無視されています。コンパイラーがインライン化に役立つと判断した場合、コンパイラーはそうしません。そこに本当のコントロールはありません。OPはすでにこれを知っており、私は引用しています:「ポイントは何ですか?」。一体誰がこれに+1を与えるのか?誤解を招く(キーワードのインライン化がインライン化を強制することを意味する)ことと、質問とは無関係です。
DavorŽdralo

2
@DavorŽdralo失礼になる必要はありません。質問をインラインを使用する理由として解釈しましたか?私のポイントは、メモリを犠牲にしてコードをより速く取得できることを示すことでした。各コンパイラはインラインキーワードを異なる方法で処理する可能性があるため、ドキュメントを確認する必要がありますが、これについては言及しませんでした。インラインで作成される余分なメモリオーバーヘッドを常に確保できるわけではないため、いつ使用するかを「ガイド」すると便利です。また、インラインが適用されるとは言いませんでした。誰かがこの回答を役立っていると感じ、+ 1を投票しました。他の人が別のレベルの経験を持っていることを尊重し、些細なことを見つけてください。
マックスキーランド
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.