我知道,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
只構造並銷燬一次。 TestTM
是嵌套的NRVO情況。該對象再次構造一次,從不復制或移動。到現在爲止還挺好。
現在我的問題 - 我怎樣才能使TestT1
的工作效率與TestTM
相同?正如您在TestT1
中看到的,第二個對象是移動構建 - 這是我想避免的。我如何更改功能transform1()
以避免任何額外的副本或移動?如果你仔細想想,TestT1
跟TestTM
沒什麼太大的區別,所以我覺得這是必須的。
對於我第二次嘗試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 = Something {}。member_variable')。並且沒有終身的臨時對象延長了它們出現的整個表達式。因此,'TestT2'中的'&&'參數和返回值不會延長超出表達式生命週期的任何臨時對象的生命週期該函數調用出現在 – Curious
也可以在這裏看到這兩個答案https://stackoverflow.com/questions/42441791/lifetime-extension-prvalues-and-xvalues,它們可能有助於解釋更多一點 – Curious