関数を1つ呼び出すだけの関数。ある変数に値を代入するだけの関数。関数を呼ぶには呼ぶ時間が必要なのですが、こんな関数を呼ぶのは時間の無駄な感じがします。今回はそれの解消方法について話します。
では、今回の要点です。
では、いってみましょう。
さて、プログラムは全てメモリ上に読み出されてその上で動いている、と第31章でいいました。これは関数も例外ではありません。
関数はメモリ上のどこかに置かれています。「関数を呼ぶ」というのは、「その関数の置かれている場所に移動する」ということになります。この「移動する」というのには時間がかかります。
「どれくらい時間がかかるか」というと、それは人間にとっては一瞬です。なのでこの時間は普通は気にすることはないのですが、1億回、10億回と繰り返すような処理ではこの時間もなかなかバカになりません。MMXペンティアム300MHzにおいて計測したところ、1000万回では10回平均で約0.48秒でした。つまり、1億回では約4.8秒です。(状況によって数値は変動すると思います。)さらに、引数を持っていればそれだけ時間も増えます。
それでも、プログラムを分かりやすくするために関数を作るのは普通です。それに、大きな関数なら関数呼び出しの時間を気にするより、処理の内容を改善する方がよっぽど処理速度を改善できるでしょう。
しかし、とても単純な関数(例えば、ある関数を呼ぶだけの関数、変数にある値を代入するだけの関数、ある変数の値を返すだけの関数など)は、さすがに呼ぶ時間が無駄な気がします。
例) void DispErrorMsg() { cout << "Error!" << endl; }
そういう小さな処理も関数にしたいときに、呼ぶ時間を無視する方法があります。
え? マクロを使えばいいんじゃないかって? そうですね。C言語だとそうなります。ですが、C++だともっときれいな方法があります。それがインライン関数です。
作り方は簡単です。戻り値の型の中に inline というのを加えればいいだけです。
inline void DispErrorMsg() { cout << "Error!" << endl; }
普通は inline は先頭に書きます。が、先頭でなければいけないわけではありません。
こうすれば、DispErrorMsg はインライン関数になり、この関数を呼んでも呼ぶ時間はかかりません。
では、なぜ呼ぶ時間がかからなくなるのでしょうか? それは、「in line(行中に)」という言葉が示しているとおり、関数の中身をその部分に埋め込むからです。ちょうどマクロのような感じです。この埋め込むことをインライン展開と呼びます。マクロも「展開」と言いましたね。
マクロと違うところは、テキストが置き換わるわけではないということと、関数の文法をとるということです。しかし、やっていることは似ていますね。
インライン関数は関数の文法を取っていることから、戻り値と引数には型があります。マクロにはこのようなものはありませんね。また、テキストが置き換わるわけではないので、マクロで起こるいろいろなバグからも解放されます。
そういった点で、インライン関数はマクロをパワーアップさせたようなものだと考えられます。他にも const 定数なども、マクロをパワーアップさせたものだと考えられます。
例えば、第49章で作った BIT マクロをインライン関数 Bit にしてみましょう。
inline unsigned int Bit(int num) { return 1 << num; }
型が保証される上に、優先順位を気にしてカッコをゴテゴテにつける必要もありません。見た目もすっきりしていいですね。
しかし、テキストが置き換わるわけではないので、マクロにしかできないことというのは依然としてあります。なので、マクロが必要でないというわけではないですね。
例えば、第57章で作った ELEM マクロは、配列のサイズは関数を通すと分からなくなるということから、インライン関数にすることはできません。他にも、第29章で作った LOOP マクロもインライン関数にすることはできません。
さて、インライン関数は処理を埋め込むわけですから、やたらめったらインライン関数を使うとプログラムサイズが増えてしまうことになるはずです。
しかし、インライン関数はプログラムサイズが肥大すると判定されれば、インライン展開されません。つまり、普通の関数になってしまうのです。これは自動的に判断されるので、自分で制御することはできません。
他にも、関数のアドレスを取得しようとすると(第31章参照)、インライン展開されません。インライン展開されると普通の関数ではなくなってしまうので、アドレスを取得できても利用できないからです。
このように、インライン関数は必ずインライン展開されるわけではないのです。しかし、それには理由があるわけで、別に変なことではありません。
今回はこれで終わりです。では、要点をまとめてみましょう。
今回で関数の話は終わりです。次回からは、変数について話していこうと思います。では。
Last update was done on 2000.7.27
この講座の著作権はロベールが保有しています