次の例を考えてみましょう。
#include <cstdio>
class object
{
public:
object()
{
printf("constructor\n");
}
object(const object &)
{
printf("copy constructor\n");
}
object(object &&)
{
printf("move constructor\n");
}
};
static object create_object()
{
object a;
object b;
volatile int i = 1;
// With #if 0, object's copy constructor is called; otherwise, its move constructor.
#if 0
if (i)
return b; // moves because of the copy elision rules
else
return a; // moves because of the copy elision rules
#else
// Seems equivalent to the above, but behaves differently.
return i ? b : a; // copies (with g++ 4.7)
#endif
}
int main()
{
auto data(create_object());
return 0;
}
そして、C ++ 11ワーキングドラフト、n3337.pdf、12.8 [class.copy]、ポイント32からのこのビットを検討してください。
ソースオブジェクトが関数パラメーターであり、コピーされるオブジェクトが左辺値で指定されていることを除いて、コピー操作の省略基準が満たされている、または満たされる場合、コピーのコンストラクターを選択するためのオーバーロード解決は次のようになります。オブジェクトが右辺値で指定されているかのように最初に実行されます。オーバーロード解決が失敗した場合、または選択したコンストラクターの最初のパラメーターのタイプがオブジェクトのタイプへの右辺値参照ではない場合(おそらくcv修飾)、オブジェクトを左辺値と見なして、オーバーロード解決が再度実行されます。[注:この2段階の過負荷解決は、コピーの省略が発生するかどうかに関係なく実行する必要があります。省略が実行されない場合に呼び出されるコンストラクターを決定し、呼び出しが省略された場合でも、選択されたコンストラクターにアクセスできる必要があります。—エンドノート]
したがって、この#if 1
例で使用する場合、オブジェクトを返すときに最初にmoveコンストラクターが試行され、次にcopyコンストラクターが試行されます。移動コンストラクターがあるため、コピーコンストラクターの代わりに使用されます。
ただし、の最後のreturn
ステートメントでcreate_object()
は、moveコンストラクターが使用されていないことを確認しました。これは言語規則の違反ではありませんか?return
言語では、最後のステートメントでmoveコンストラクターを使用する必要がありますか?