首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >嵌套函数调用的C++命名返回值优化

嵌套函数调用的C++命名返回值优化
EN

Stack Overflow用户
提问于 2017-06-10 17:13:28
回答 1查看 915关注 0票数 7

我知道NRVO允许一个函数构造一个对象并按值返回该对象,而不需要复制甚至移动操作。它发现它还可以使用嵌套函数调用,允许您从另一个函数调用的返回值构造对象。

请考虑以下程序及其输出,如注释所示:

(来自Visual 2017版本15.2版本的输出,发布版本build)。

代码语言:javascript
复制
#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案例。同样,对象只构造一次,从不复制或移动。到目前一切尚好。

现在谈谈我的问题--如何使TestT1TestTM一样高效地工作?正如您在TestT1中看到的,第二个对象是move构造的--这是我想要避免的事情。如何更改函数transform1()以避免任何额外的复制或移动?如果您仔细想想,TestT1TestTM并没有太大的不同,所以我有一种感觉,这是一种必须是可能的事情。

第二次尝试是TestT2,我尝试通过RValue引用传递对象。这消除了额外的移动构造函数,但不幸的是,这会导致在完成对象之前调用析构函数,这并不总是理想的。

更新:

我还注意到,只要确保在语句结束后不使用对象,就可以使用引用使其工作:

代码语言:javascript
复制
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()

这样安全吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-06-10 17:18:43

这发生在Test1中,因为编译器明确不允许从函数的参数列表中的值参数应用NRVO。在Test1中,您接受W实例的值作为函数参数,因此编译器不能在返回时删除移动。

参见Why are by-value parameters excluded from NRVO?和我与Hinnant在评论中对这个问题的讨论,each return function by move

由于这一点,您无法使Test1像以前那样高效地工作。

标准中的相关引文

15.8.3复制/移动class.copy.elision

  1. 当满足某些条件时,允许实现省略类对象的复制/移动构造,.
代码语言:javascript
复制
- in a `return` statement in a function with a class return type, when the _expression_ is the name of a non-volatile automatic object (other than a function parameter or a variable introduced by the _exception-declaration_ of a _handler_ (18.3)) with the same type (ignoring cv-qualification) as the function return type, the copy/move operation can be omitted by constructing the automatic object directly into the function call’s return object

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44475982

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档