ikautak.log

C/C++, Python, CUDA, Android, Linux kernel, Network, etc.

More Effective C++ 項目19 テンポラリオブジェクトの由来を理解しよう

新訂版 More Effective C++ (AddisonーWesley professional co)

新訂版 More Effective C++ (AddisonーWesley professional co)

  • 作者: スコット・メイヤーズ,安村通晃,伊賀聡一郎,飯田朱美,永田周一
  • 出版社/メーカー: ピアソンエデュケーション
  • 発売日: 2007/06/29
  • メディア: 単行本(ソフトカバー)
  • 購入: 8人 クリック: 129回
  • この商品を含むブログ (43件) を見る

項目19 テンポラリオブジェクトの由来を理解しよう

ほんの短い間だけ必要な変数をテンポラリと呼ぶことが多い。

template<class T>
void swap(T& object1, T& object2) {
  T temp = object1;
  object1 = object2;
  object2 = temp;
}

この例で、tempはテンポラリと呼ばれるが、C++では一時的ではなく、れっきとしたローカルオブジェクトである。

C++は本当の意味でのテンポラリオブジェクトはソースコードに出てこないので見えない。 このような名無しオブジェクトは次の2つのケースで生成されることが多い。

関数呼び出しの暗黙的な型変換

1つ目は、ある関数に渡す型が、そのオブジェクトがバインドされる型と異なる場合に起きる。

// 文字列中のある文字の数を返す
size_t countChar(const string& str, char ch);

char buffer[MAX_LEN];
char c;

// 文字と文字列を読む
cin >> c >> setw(MAX_LEN) >> buffer;

cout << "There are " << countChar(buffer, c)  // char配列を渡す
     << " occurrences of the character " << c
     << " in " << buffer << endl;

countCharの呼び出しでは、第1の実引数はchar配列だが、関数の引数はconst string&である。
C++コンパイラはstring型のテンポラリを作ってこの問題を回避する。
テンポラリオブジェクトは、bufferを引数にstringのコンストラクタを読んで初期化し、引数のstrにバインドされ、countCharの処理が終了すると自動的に破棄される。

このテンポラリはconst参照でないと起きない。非const参照にchar配列を渡してもコンパイルエラーとなる。

関数がオブジェクトを返すとき

2つ目は関数の戻り値がオブジェクトの場合。
operator+がオペランドの合計を返す場合を考える。

const Number operator+(const Number& a, const Number& b);

この関数の戻り値はテンポラリとなる。
operator+は呼ばれるたびにオブジェクトの生成と破棄を繰り返す。 このケースではoperator+=を使うことで余計なコストをかけなくて済む。(項目22で出てくるらしい)
しかし、オブジェクトを返す関数の多くは戻り値の生成と破棄を避ける方法はない。

まとめ

テンポラリオブジェクトが生成されること自体が無駄なので、生成しないで済む場合は出来る限り生成しない。
const参照引数や、オブジェクトを返す関数はテンポラリオブジェクトが作られると思ったほうが良い。
テンポラリオブジェクトが作られそうな場所がわかることが重要。