我知道NRVO允许一个函数在没有复制或移动操作的情况下构造并通过值返回该对象。它还可以与嵌套函数调用一起使用,允许您从另一个函数调用的返回值构造对象。
请考虑以下程序及其输出,如注释所示: (来自Visual Studio 2017版本15.2,发布构建的输出。)
这样做安全吗?
请考虑以下程序及其输出,如注释所示: (来自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
不工作?我以为引用会延长临时对象的生命周期? - Barnettauto&& val = Something{}.member_variable
)时才会延长。没有其生命周期延长的临时对象将持续整个它们出现的表达式。因此,在TestT2
中的&&
参数和返回值不会延长任何超出函数调用所在表达式的生命周期的临时对象的寿命。 - Curious