しるふぃずむ

どうもプログラマです。好きなものはC#とジンギスカンです。嫌いなものはJava。プログラムおもちろいね。

Initialization of Class Objects by rvalues

「rvalueによるクラスオブジェクトの初期化」.
Ideone.com - bcRKnw - Online C++0x Compiler & Debugging Tool
先日の記事の理解していなかった挙動はどうやらこれによるものだったようです.
N1610の変更点に
「rvalueオブジェクト全体から直接初期化する」との記述がありました.
同じ型のオブジェクトから初期化する際,従来はコピーコンストラクタを呼ぶしかなかったものを
条件を満たす場合にムーブコンストラクタすら呼ばずに直接変数の領域に構築できる機能と捉えて良いでしょうか.

Bar x(Bar{});

一時領域に作られてからコピー・ムーブするのではなくxの領域に直接構築.
デフォルトコンストラクタ一回だけが呼ばれます.

Bar y(func());

rvalueはコンストラクタだけではありません,
関数からオブジェクトを返す場合も直接構築が可能です.

Bar z(std::move(x));

この場合はムーブされます.
xの領域とzの領域は違うので,この場合は適用の使用がありません.
つまりxvalueには適用できず,prvalueである必要があるということでしょうか.

副作用があるとスキップされてこまったことになりそうですが,
そんなものはそんなことになる設計が悪い,で済みそうですかね.
意識しなくても恩恵に預かれる機能と言えそうです.

#include <iostream>

struct Bar
{
	Bar(){ std::cout << "default ctor" << std::endl; } 
	Bar(Bar const&){ std::cout << "copy ctor" << std::endl; }
	Bar(Bar&&){ std::cout << "move ctor" << std::endl; }
	Bar&operator=(Bar const&){ std::cout << "copy subst" << std::endl; return *this; }
	Bar&operator=(Bar&&){ std::cout << "move subst" << std::endl; return *this; }
};

Bar func()
{
	return {};
}

int main(int, char*[])
{
	Bar x(Bar{});
	Bar y(func());
	Bar z(std::move(x));

	return 0;
}

output

default ctor
default ctor
move ctor