あなたが言語を学んでいるだけなら、あなたは本当にこれについて心配するべきではありません。他の方法で証明されるまで、十分に速く検討してください。とはいえ、ここには誤解を招く答えや不完全な答えがたくさんあるので、記録のために、微妙な意味のいくつかを具体化します。あなたのクラスを考えてみましょう:
class Booth
{
public:
int get_tickets_sold();
void set_tickets_sold();
private:
int tickets_sold;
};
getおよびset関数の実装(定義と呼ばれる)はまだ指定されていません。クラス宣言内で関数本体を指定した場合、コンパイラーは、それらがインライン化されることを暗黙的に要求したと見なします(ただし、関数本体が大きすぎる場合は無視できます)。後でキーワードを使用してそれらを指定するとinline
、まさに安全な効果があります。要約すると...
class Booth
{
public:
int get_tickets_sold() { return tickets_sold; }
...
...と...
class Booth
{
public:
int get_tickets_sold();
...
};
inline int Booth::get_tickets_sold() { return tickets_sold; }
...同等です(少なくとも、標準で期待されることに関しては、個々のコンパイラのヒューリスティックは異なる場合があります。インライン化は、コンパイラが自由に無視できるようにする要求です)。
関数本体が後でinline
キーワードなしで指定された場合、コンパイラーはそれらをインライン化する義務を負いませんが、それでもそうすることを選択できます。それらが同じ変換単位(つまり、コンパイルしている.cc / .cpp / .c ++ / etc。「実装」ファイルまたは直接または間接的に含まれているヘッダー)にある場合は、そうなる可能性がはるかに高くなります。 実装がリンク時にのみ利用可能である場合、関数はまったくインライン化されない可能性がありますが、特定のコンパイラとリンカが相互作用して連携する方法によって異なります。それは単に最適化を可能にし、魔法を期待することの問題ではありません。これを証明するために、次のコードを検討してください。
// inline.h:
void f();
// inline.cc:
#include <cstdio>
void f() { printf("f()\n"); }
// inline_app.cc:
#include "inline.h"
int main() { f(); }
これを構築する:
g++ -O4 -c inline.cc
g++ -O4 -o inline_app inline_app.cc inline.o
インライン化の調査:
$ gdb inline_app
...
(gdb) break main
Breakpoint 1 at 0x80483f3
(gdb) break f
Breakpoint 2 at 0x8048416
(gdb) run
Starting program: /home/delroton/dev/inline_app
Breakpoint 1, 0x080483f3 in main ()
(gdb) next
Single stepping until exit from function main,
which has no line number information.
Breakpoint 2, 0x08048416 in f ()
(gdb) step
Single stepping until exit from function _Z1fv,
which has no line number information.
f()
0x080483fb in main ()
(gdb)
実行がmain()の0x080483f3からf()の0x08048416になり、main()の0x080483fbに戻ったことに注意してください...明らかにインライン化されていません。これは、関数の実装が簡単であるという理由だけでインライン化を期待できないことを示しています。
この例は、オブジェクトファイルの静的リンクを使用していることに注意してください。明らかに、ライブラリファイルを使用する場合は、クライアントコードを再コンパイルせずにライブラリを更新できるように、関数のインライン化を特に避けたい場合があります。とにかくロード時に暗黙的にリンクが行われる共有ライブラリの場合はさらに便利です。
非常に多くの場合、些細な関数を提供するクラスはinline
、パフォーマンスが重要なループ内でそれらの関数が呼び出されることが期待できる場合、2つの形式の期待されるインライン関数定義(つまり、クラス内またはキーワード付き)を使用しますが、対抗する考慮事項は、関数の実装への変更を取得するために、単に再リンクするのではなく、クライアントコードを強制的に再コンパイルし(比較的遅く、自動トリガーがない可能性があります)、再リンクします(高速、共有ライブラリは次の実行で発生します)。
この種の考慮事項は厄介ですが、これらのトレードオフを慎重に管理することで、企業でのCおよびC ++の使用を、数千万の回線および数千の個別のプロジェクトに拡張でき、すべてが数十年にわたってさまざまなライブラリを共有できます。
もう1つの小さな詳細:球場の図として、アウトオブラインのget / set関数は、通常、同等のインラインコードよりも約1桁(10倍)遅くなります。これは、CPU、コンパイラ、最適化レベル、変数タイプ、キャッシュのヒット/ミスなどによって明らかに異なります。