質問
クラス定義自体の内部でメンバー関数を定義する場合、必然的にインラインで扱われますか、それとも無視できるコンパイラへの単なるリクエストですか。
解決
はい、クラス本体内で定義されている関数は暗黙的です inline
.
(宣言された他の機能と同様 inline
それは、コンプライアが関数が呼び出される場所でインライン拡張を実行する必要があるという意味ではありません。「1つの定義ルール」の許可された緩和を可能にし、定義をすべての翻訳ユニットに含める必要があるという要件と組み合わせて、機能が使用されます。)
他のヒント
他の人が述べたように、クラス内で定義された方法は、自動的にインラインで要求されます。その理由を理解するのに役立ちます。
そうではなかったと仮定します。そのような関数のコードを生成する必要があり、それが呼ばれるすべての場所では、サブルーチン命令へのジャンプは、リンカーを介して場所を参照する必要があります。
class A {
public:
void f() { ... your code ... }
};
このコードが見られるたびに、インラインでない場合、コンパイラはそれを生成する必要があると仮定することしかできないため、シンボルを生成します。このようなものだったとします:
a__f_v:
そのシンボルがグローバルだった場合、このクラスコードを異なるモジュールに複数回含める場合、リンク時に定義されたシンボルエラーが増加します。したがって、それはグローバルになることはできません。代わりに、それはローカルファイルです。
上記のヘッダーファイルを多くのモジュールに含めると想像してください。それぞれで、そのコードのローカルコピーを生成します。これはまったくコンパイルしないよりも優れていますが、実際に1つだけが必要な場合、コードの複数のコピーを取得します。
これにより、次の結論が導かれます。コンパイラが関数をインラインにしない場合は、一度どこかで宣言し、インラインを要求しない方がかなり良くなります。
残念ながら、インラインではないものは、ポータブルではありません。コンパイラライターによって定義されています。良い経験則は、常にすべてのライナー、特にオーバーヘッドを削除するときにインラインをインラインと呼ぶすべての機能を常に作成することです。 3行以下の線形コードはほぼ確実に問題ありません。しかし、コードにループがある場合、問題はコンパイラがインラインを許可するかどうか、そしてそれがあなたが望むことをしたとしても、あなたがどれだけの利益を見るかを要するかどうかです。
このインラインコードを検討してください。
inline int add(int a, int b) { return a + b; }
プロトタイプがソースコードにあるほど小さいだけでなく、インラインコードによって生成されたアセンブリ言語は、ルーチンへの呼び出しよりも小さいです。したがって、このコードは小さく、より速いです。
そして、あなたがたまたま定数を通過している場合:
int c= add(5,4);
コンパイル時に解決され、コードはありません。
GCCでは、最近、コードがインラインでなくても、ファイルにローカルであれば、とにかく卑劣にインラインになることに気付きました。独立したソースモジュールで関数を宣言した場合にのみ、コールを最適化しません。
スペクトルのもう一方の端で、1000行のコードにインラインを要求するとします。コンパイラがそれに沿って十分に愚かであっても、保存するのはコール自体だけです。コストは、それを呼び出すたびに、コンパイラがそのコードをすべて貼り付ける必要があることです。 、コードはルーチン * nのサイズによって成長します。したがって、10行以上の大きなものは、非常に少数の回数と呼ばれる特別なケースを除いて、インランスの価値がほとんどありません。その例は、他の2人だけが呼ぶプライベートな方法にあるかもしれません。
ループを含むメソッドをインラインにするように要求する場合、それは多くの場合、少数回を実行することが多い場合にのみ理にかなっています。ただし、100万回反復するループを検討してください。コードがインラリングされていても、通話に費やされる時間の割合は小さくなります。とにかく大きくなる傾向があるループが入っている方法がある場合、それらはヘッダーファイルから削除する価値があります。なぜ利益を提供するつもりはありません
コンパイラによって必然的にインラインの要求として扱われます - それは無視できます。ヘッダー(空の仮想デストラクタなど)にいくつかの関数を定義するためのいくつかのイディオムと、必要なヘッダー定義(テンプレート関数)がありますが、それ以外 GOTW#33 詳細については。
コンパイラは、あなたがそれに決して尋ねたことのないインライン関数さえさえするかもしれないと指摘している人もいますが、それが関数をインラインにすることを要求する目的を打ち負かすかどうかはわかりません。
確かにインラインドされていますが、インラインリクエストはコンパイラによって無視できます。
これは、コンパイラへの無視できるリクエストです。
2003年のISO C ++標準は言います
7.1.2/2インライン仕様を使用した関数宣言(8.3.5、9.3、11.4)は、インライン関数を宣言します。インライン仕様は、コールポイントでの関数本体のインライン置換が通常の関数呼び出しよりも優先されることを実装に示します
機構。このインラインを実行するために実装は必要ありません
コールポイントでの代替。ただし、これがインラインであっても
代替は省略されており、7.1.2で定義されたインライン関数の他のルールは依然として尊重されます。7.1.2/3クラス定義内で定義された関数はインラインです
関数。インライン仕様は、ブロックスコープ関数宣言に表示されないものとします。7.1.2/4インライン関数は、すべての翻訳ユニットで定義されなければなりません
それが使用されており、すべてでまったく同じ定義があります
ケース(3.2)。 [注:インライン関数への呼び出しに遭遇する可能性があります
そのdefi-nitionが翻訳ユニットに表示される前に。 ]外部リンケージを持つ関数が1つの翻訳ユニットでインラインで宣言された場合、表示されるすべての翻訳単位でインラインと宣言されるものとします。診断は必要ありません。外部リンケージを持つインライン関数は、すべての翻訳ユニットで同じアドレスを持つものとします。外部インラインの静的ローカル変数
関数は常に同じオブジェクトを指します。文字通りの文字列
外部インライン関数は、異なる翻訳で同じオブジェクトです
ユニット。
まとめてはならない2つのことがあります。
- 関数をインラインとしてマークする方法:署名の前にインラインで定義するか、宣言ポイントで定義します。
- コンパイラがそのようなインラインマーキングを扱うもの:関数をインラインとしてどのようにマークしたかに関係なく、コンパイラによる要求として扱われます。