アルゴリズムのそれってこーいうことか(その2)

関数オブジェクトのコピーコストって?

(*A)でfor_eachの第3引数に渡している SIncrementer1() ってどういう意味か知っていますか?

という前回のお話の続きです。
という話ですが、答えは簡単にいうと、クラス名や構造体名の後に丸カッコをつけると、基本的に(*B)そのコンストラクタによる一時変数が生成されるという意味になるみたいです。つまり

int hoge = 5;
{
	SIncrementer1 tmp;
	tmp( hoge ); // hogeは6になる
}

と、

int hoge = 5;
SIncrementer1()( hoge ); // hogeは6になる

はほぼ等価*1だということです。後者は丸カッコが連続して気持ち悪いですが、あ、ここで一時変数が作成されているのかと思うと不自然ではないですよね。
しかしここで罠なのが、

	SIncrementer1 tmp;
	for_each( ..., tmp );

	for_each( ..., SIncrementer1() );

同じではないということです。前者はコンストラクタが3回呼ばれて、後者は2回呼ばれるのです。

  • 前者 : コンストラクタ×1, コピーコンストラクタ×2
  • 後者 : コンストラクタ×1, コピーコンストラクタ×1

for_eachのアルゴリズム上最後に関数オブジェクトを返却するのでコピーコンストラクタ1回分はどうしても発生してしまうのですが、
では、前者のコピーコンストラクタの残り1回はどこで発生するのでしょうか?それはfor_eachの引数として渡した時にです。オブジェクトが値渡しされたときにコピーコンストラクタって走る…ものでしたよね(ちょいと記憶があやふや)。
ではここで疑問が発生します。なぜ後者の書き方をした場合、コピーコンストラクタの回数が抑えられるのでしょうか?
いきなりアルゴリズムから脱線している気もしますが、次は本線に戻る予定です。
(続く)

*1:関数オブジェクトの寿命に違いがあるから「ほぼ」と書きました