NRVOは、コピーを作成したり操作を移すことなく、オブジェクトを構築してそのオブジェクトを値で返すことができることを知っています。また、ネストされた関数呼び出しでも機能し、別の関数呼び出しの戻り値からオブジェクトを構築できるようになりました。 ネストされた関数呼び出しによるC++の名前付き戻り値の最適化
は、次のプログラムを考えてみてください、それはコメントに示すように、出力です:(。のVisual Studio 2017、バージョン15.2、リリースビルドからの出力)#include <stdio.h>
class W
{
public:
W() { printf("W::W()\n"); }
W(const W&) { printf("W::W(const W&)\n"); }
W(W&&) { printf("W::W(W&&)\n"); }
W& operator=(const W&) { printf("W::operator=(const W&)\n"); }
W& operator=(W&&) { printf("W::operator=(W&&)\n"); }
~W() { printf("W::~W()\n"); }
void Transform() { printf("W::Transform()\n"); }
void Run() { printf("W::Run()\n"); }
};
W make()
{
W w;
return w;
}
W transform_make()
{
W w{ make() };
w.Transform();
return w;
}
W transform1(W w)
{
w.Transform();
return w;
}
W&& transform2(W&& w)
{
w.Transform();
return std::move(w);
}
int main() // Program output:
{
printf("TestM:\n"); //TestM:
{ //W::W()
W w{ make() }; //W::Run()
w.Run(); //W::~W()
}
//TestTM:
printf("TestTM:\n"); //W::W()
{ //W::Transform()
W w{ transform_make() }; //W::Run()
w.Run(); //W::~W()
}
//TestT1:
printf("TestT1:\n"); //W::W()
{ //W::Transform()
W w{ transform1(make()) }; //W::W(W&&)
w.Run(); //W::~W()
} //W::Run()
//W::~W()
printf("TestT2:\n"); //TestT2:
{ //W::W()
W&& w{ transform2(make()) }; //W::Transform()
w.Run(); //W::~W()
} //W::Run()
}
TestM
は、通常のNRVOケースです。オブジェクトW
は、1回だけ構築され、破壊されます。 TestTM
はネストされたNRVOのケースです。再びオブジェクトは一度だけ作成され、コピーも移動もされません。ここまでは順調ですね。
今、私の質問に - TestT1
をTestTM
と同じ効率で動作させるにはどうしたらいいですか? TestT1
に見られるように、2番目のオブジェクトが移動されました。これは避けたいものです。どのように追加のコピーや移動を避けるために機能transform1()
を変更することができますか?あなたがそれについて考えるなら、TestT1
はTestTM
と大きく異なるわけではないので、これが可能でなければならないと感じています。
私の2回目の試行では、TestT2
のために、私はRValue参照でオブジェクトを渡そうとしました。これは、余分な移動コンストラクタを削除しましたが、残念ながら、これは、オブジェクトを処理する前にデストラクタを呼び出す原因となりますが、これは必ずしも理想的ではありません。
更新:
W&& transform2(W&& w)
{
w.Transform();
return std::move(w);
}
void run(W&& w)
{
w.Run();
}
printf("TestT3:\n"); //TestT3:
{ //W::W()
run(transform2(make())); //W::Transform()
} //W::Run()
//W::~W()
は、次のとおりです。
私もそれは限り、あなたは文の終わりを超えてオブジェクトを使用していないことを確認して、参照を使用して動作させることが可能であることに注意してくださいこれは安全ですか?
ありがとう、私は理解していると思います。しかし、なぜ 'TestT2'は動作しませんか?私はその参照が一時的なオブジェクトの存続期間を延ばすと思った? – Barnett
@Barnett参照にバインドされたオブジェクトの存続期間は、バインドされるオブジェクトが完全なオブジェクト(ほとんどの場合、その値がprvalueの場合)または完全なオブジェクトの完全なサブオブジェクト(たとえば、auto && val =何か{}。member_variable')。 'TestT2'の' && 'パラメータと戻り値は、式の存続期間を超えてバインドされた一時的なものの存続期間を延長しません関数呼び出しは – Curious
に表示されます。両方の答えはhttps://stackoverflow.com/questions/42441791/lifetime-extension-prvalues-and-xvaluesで確認できます。 – Curious