作者:冷月荐向_878 | 来源:互联网 | 2023-02-01 16:13
我知道NRVO允许函数构造一个对象并按值返回该对象而不需要复制或甚至移动操作的成本.它发现它也适用于嵌套函数调用,允许您从另一个函数调用的返回值构造对象.
请考虑以下程序及其输出,如注释中所示:(
Visual Studio 2017的输出,版本15.2,发布版本.)
#include
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()
这样做安全吗?