2016-05-11 7 views
1

インライン関数をヘッダーに定義する理由は、その関数が呼び出される各コンパイル単位には、呼び出しを置き換えるか、それを置き換えるために全体の定義。私の質問は、コンパイラがインライン展開の最適化を行うことができる場合、ヘッダファイルに定義を入れることです。なぜなら、関数が定義されているcppファイルを掘り下げる必要があるからです。コンパイラが独自の機能でインライン関数をインライン化できるのであれば、インライン関数をヘッダーに "定義"する必要があります

つまり、コンパイラは、ヘッダーファイルで関数 "宣言"を表示し、対応するcppファイルに移動し、そこから定義を取り出して、関数内の適切な場所に貼り付けることができます。他のcpp。これが当てはまる場合、なぜコンパイラが他のcppファイルに "見る"ことができないかのように、ヘッダに関数を定義することが主張されています。

MSDNはOB2 /最適化設定についてこう述べています。

OB2 /デフォルト値。インライン、__インライン、または__forceinline、、およびコンパイラが(私の強調)を選択したその他の関数としてマークされた関数の展開を許可します。

+1

"対応するcppファイル"はありません。関数定義は、任意のソースファイル、または後でプログラムにリンクされる任意のオブジェクトファイルまたはライブラリに含めることができます。言い換えれば、このケースは全く与えられていない。 – molbdnilo

+0

@molbdniloわかりました、申し訳ありませんが、私は "対応するcppファイル"と言って間違っていました。私はまだコンパイラがインラインキーワードを持たずにどのように機能をインライン化できるのか不思議です。たとえば、MSDNは次のように言っています: "/ Ob2。デフォルト値。インライン、__inline、または__forceinline、およびコンパイラが選択する他の関数としてマークされた関数の展開を許可します。"これはリンカ段階ではなく推測している段階です。 – Zebrafish

答えて

3

ヘッダーファイルのインライン関数の定義を(少なくとも、指定されたコンパイル単位で関数をインライン展開するときにインプリメンテーションに表示される)何らかの形で提供する理由は、C++標準の要件です。

しかし、標準は、プリプロセッサ、コンパイラ、リンカなどのツールチェーンやその一部などの実装が少しスマートにならないようにするためのものではありません。

いくつかの特定の実装では、少しスマートな作業が行われるため、実際にはコンパイラには表示されない状況でも関数をインライン展開できます。たとえば、基本的な「すべてのソースファイルをコンパイルしてリンクする」ツールチェーンでは、スマートリンカは関数が小さく、数回しか呼び出されないことを認識し、インライン展開するポイント(例えば、関数を呼び出す文が別のコンパイル単位にあるため、関数自体は別のコンパイル単位にあります)コンパイラはインライン展開を行いません。

実際には、標準で実装されていることを防ぐことはできません。これは、単にすべての実装の動作のための最低限の要件のセットを述べています。

本質的に、コンパイラがインライン化される関数の可視性を持つという要件は、標準からの最小要件です。プログラムがそのように記述されている場合(例えば、インライン化されるすべての関数がヘッダファイルで定義されている場合)、標準ではすべての(標準に準拠した)実装で動作することが保証されます。

しかし、これはわれわれのスマートなツールチェーンにとってどういう意味ですか?よりスマートなツール連鎖は、適切な形式のプログラム(これらの関数を使用するすべてのコンパイル単位でインライン関数を定義するプログラムを含む)から正しい結果を生成する必要があります。私たちのツールチェーンは、よりスマートな操作(例えば、コンパイルユニット間の覗き見)を許可されていますが、コードが別のツールチェーンによって拒否されるようなスマートな動作(コンパイラ間でのコンパイラの覗き見など)

最終的に、C++実装のすべて(ツールチェーン、標準ライブラリなど)は、C++標準の要件に準拠する必要があります。逆のことは真実ではありません。一つの実装は、標準よりもスマートなことを行うかもしれませんが、他の実装が互換性のある方法で動作するという要件を生成しません。

技術的には、インライン化はコンパイラの機能に限定されません。コンパイラまたはリンカで発生する可能性があります。実行時にも発生する可能性があります。たとえば、「ジャストインタイム」テクノロジは、後続のパフォーマンスを向上させるために、実行可能コードを数回実行した後に再構成することができます[通常、仮想マシン環境で発生します自己修正実行可能ファイルに関連する問題を回避しながら、そのような技術の利点]。

+0

優れた答えと非常に教育的。私が理解していることは、C++言語の標準が満たされていなくても、コンパイラとリンカーが余分なステップを踏むかもしれないということです。この場合、ヘッダーに完全な定義を提供します。コンパイラやリンカのどちらかでコンパイル単位を "覗く"ことで、あなたの言語を使ってインライン最適化を行うことができます。ベストプラクティスではヘッダーの宣言とCPPの定義がありますが、インライン展開はこれに反するため、面白いですが、これまで慣れてきたことです。ありがとう。リンク時に – Zebrafish

+0

のインライン展開にはコンパイラの完全な機能が必要です。これは、通常のリンカーができることではありません。リンク時の最適化は存在しますが、コンパイラの中間表現をオブジェクトファイルに格納することで動作します。最終的なasmを読み込み、それに基づいてインライン展開するのではありません。 (これは少なくともgccとclangの場合であり、私はLTOを実行できる他のコンパイラを想定しています)。 –

3

コンパイラは伝統的にこれを行うことはできません。古典的なモデルでは、コンパイラは一度に1つのcppファイルしか見ることができず、他のcppファイルにはアクセスできません。このcppファイルコンパイラのうち、いわゆるオブジェクトファイルがplatofirmネイティブ形式であり、1970年代の効果的なリンカーを使用してリンクされているのではなく、ハンマーと同じように愚かです。

このモデルはゆっくりと進化しています。より効果的なリンク時最適化(LTO)リンカーは、cppコードが何であるかを認識し、独自のインライン展開を実行できます。しかし、リンク時の最適化モデルであっても、コンパイル済みのインライン化と最適化はリンク時よりも効率的です。つまり、cppコードをリンクに適した中間形式に変換すると、多くの重要なコンテキストが失われます。

+0

私は参照してください。 Visual Studioのリリースモードのデフォルトの最適化は、 "/ Ob2。デフォルト値。インライン、__インライン、__forceinline、およびコンパイラが選択するその他の関数としてマークされた関数の展開を許可します。"それ自身のインライン化? – Zebrafish

+0

@TitoneMaurice、私はMSVCツールチェーンに精通していません、ごめんなさい。 – SergeyA

2

インラインキーワードは、呼び出された時点で実装を拡張するだけではなく、実際には関数の複数の定義が特定の変換単位に存在する可能性があることを主に宣言することです。それがあれば、コンパイラが関数をインライン展開するために、それは私が

Why are class member functions inlined?

Is "inline" implicit in C++ member functions defined in class definition

+0

ありがとうございます。あなたが与えた2番目のリンクからの答えを引用する: "インラインキーワードは、インライン展開とはまったく関係ありません。機能の複数の同一の定義が異なるTUで許可されるかどうかです。" – Zebrafish

1

はそれがはるかに簡単です:)よりもはるかに優れて説明することができ

これは前に他の質問で取り上げてきました、その機能の定義を見てきました。コンパイラに、その関数を使用するすべての変換単位で関数の定義を参照させる最も簡単な方法は、ヘッダーに定義を入れ、その関数が使用されるどこででもそのヘッダを#includeにすることです。その場合、コンパイラ(実際にはリンカ)が複数の翻訳単位でその関数の定義を見ることについて不平を言わないように、定義をinlineとマークする必要があります。

関連する問題