LoginSignup
1
1

More than 3 years have passed since last update.

勉強記録 7日目 〜マクロで定義する関数より、inline関数を使おう〜 - Effective C++ 第3版 -

Posted at

 はじめに

Effective C++ 第3版の2項7ページから勉強していきます。
今回は、「マクロで定義する関数より、inline関数を使おう」についです。

Effective C++ 第3版 - 2項 #defineより、const, enum, inlineを使おう -

マクロで定義する関数より、inline関数を使おう

マクロで定義する関数の問題点

#defineを使って定義するマクロは、関数のように働きますが、関数呼び出しのオーバーヘッドがありません。(呼び出し時間が少ない)
しかし、#defineを使ってマクロを定義する場合、注意する必要があります。
以下に、#defineのよくない利用方法を示します。

#define CALL_WITH_MAX(a, b) f((a) > (b) ? (a) : (b));

これは、与えられた2つの引数のうち大きい方を引数にして関数fを呼び出すマクロです。
注意点1つめとして、このようなマクロを書くときには、仮引数を丸カッコで囲まないといけません。
しかし、正しく丸カッコをつけても、次のようなコードが書かれれば、困ったことになります。

CALL_WITH_MAX(++a, b);  // aが2回インクリメントされる
CALL_WITH_MAX(++a, b + 10);  // aが1回インクリメントされる

上のコードでは、関数fが呼び出される前にaが何回インクリメントされるかは、引数によって変わってしまいます。

なぜか?

CALL_WITH_MAX(++a, b);  // aが2回インクリメントされる

では、マクロから関数fに与えられる引数は、

(++a) > (b) ? (++a) : (b)

のようになります。
そのため、(++a) > (b) が True ならインクリメントが2回行われてしまう。

この問題を解決するためにインライン(inline)関数を用います。
インライン関数とは、「in line(行中に)」という言葉が示しているとおり、関数の中身をその部分に埋め込みます。
そのため、インライン関数は、呼び出しにかかる時間が普通の関数を短い利点を持つ。
マクロと違う点は、テキストが置き換わるわけではないということと、戻り値と引数に型があるということです。

インライン関数を用いて、先ほどの「与えられた2つの引数のうち大きい方を引数にして関数fを呼び出す」処理を書くと、

inline void callWithMax(const T& a, const T& b) {
  f(a > b ? a : b);
}

のようになります。
このインライン関数を呼び出す処理は、

callWithMax(++a, b);     // aが1回インクリメント
callWithMax(++a, b + 10);  // aが1回インクリメント

のようになります。
インライン関数を用いることで、仮引数を丸カッコで囲む必要もなく、引数を複数回評価されるといった心配もなくなります。

以下に今回、勉強でしようしたコードと実行結果を示します。

サンプルコード

#include <iostream>

#define CALL_WITH_MAX(a, b) f((a) > (b) ? (a) : (b));

void f(const int& x) { std::cout << __func__ << " : value = " << x << std::endl; }

template <typename T>
inline void callWithMax(const T& a, const T& b) {
  f(a > b ? a : b);
}

int main(int argc, char* argv[]) {
  std::cout << "2_inline_define.cpp" << std::endl;
  int a = 5;
  int b = 0;
  CALL_WITH_MAX(++a, b);  // aが2回インクリメントされる
  std::cout << "a : " << a << std::endl;
  std::cout << "b : " << b << std::endl;
  CALL_WITH_MAX(++a, b + 10);  // aが1回インクリメントされる
  std::cout << "a : " << a << std::endl;
  std::cout << "b : " << b << std::endl;

  std::cout << "\n############################################\n" << std::endl;

  a = 5;
  b = 0;
  callWithMax(++a, b);  // aが1回インクリメント
  std::cout << "a : " << a << std::endl;
  std::cout << "b : " << b << std::endl;
  callWithMax(++a, b + 10);  // aが1回インクリメント
  std::cout << "a : " << a << std::endl;
  std::cout << "b : " << b << std::endl;
}

実行結果

2_inline_define.png

参考文献

https://www.amazon.co.jp/gp/product/4621066099/ref=dbs_a_def_rwt_hsch_vapi_taft_p1_i0

1
1
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1