前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >浅析RVO

浅析RVO

作者头像
程序员的园
发布2024-07-18 13:27:17
630
发布2024-07-18 13:27:17
举报
文章被收录于专栏:程序员的园——原创文章

RVO(Return Value Optimization,返回值优化)是C++中的一种优化技术,用于避免不必要的对象拷贝,提高程序的性能和效率。NRVO(Named Return Value Optimization,命名返回值优化)是RVO的一种特殊情况,隶属于RVO范畴。

如下的代码分别是RVO和NRVO的使用示例。

代码语言:javascript
复制
People using_rvo()
{
return People{10,"tommy"};
}
People using_nrvo()
{
auto p = People{ 10,"tommy" };
return p;
}

RVO它通过在函数返回时,将局部对象直接构造在函数调用方的目标对象上,避免了额外的对象拷贝操作。NRVO是在函数返回时,如果函数中的局部对象被命名为返回值,并且没有其他对象被命名为返回值,编译器可以直接在调用函数内部构造返回值对象,避免了对象拷贝操作。

RVO的原理为当编译器检测到适用于RVO的情况时,在编译源代码时就会进行优化。这意味着编译器会检测适用情况,同理,RVO必定存在其不适用的场景——其使用限制,接下来会详述其使用限制。

使用限制

1. 返回值类型不能是引用类型

参考如下的示例代码

代码语言:javascript
复制
CPeople& using_nrvo_with_ref2()
{
  auto p = CPeople{ 10,"tommy" };
  return p;
}

针对于普通局部变量而言,msvc出现崩溃(崩溃于拷贝构造函数中),gcc中会出现段错误,返回局部变量的引用本就是危险的行为,当局部变量析构后会出现未定义行为,所以出现崩溃以及段错误都是理所当然的。禁止传递局部变量的引用。

针对于静态局部变量而言,msvc和gcc均会执行一次构造一次拷贝构造函数,即静态局部变量不存在RVO。

2. 返回值不能被异常处理包围

如下的示例代码中,返回值被try-catch包围,在gcc下未没有rvo,依次执行了构造-移动构造-析构,但是msvc下发生了rvo,

代码语言:javascript
复制
CPeople using_nrvo_with_exception()
{
  try
  {
    auto p = CPeople{ 10,"tommy" };
    return p;
  }
  catch (const std::exception&)
  {
    throw std::runtime_error("");
  }

}

3. 函数中不能有其他返回值

如下的示例代码中,依据条件,会有相同类型但是不同值的返回值——即含有其他的返回值,gcc中并没有rvo,依次执行了构造-移动构造-析构,但是msvc下发生了rvo。

代码语言:javascript
复制
CPeople using_nrvo_with_mrv(bool flag)
{
  if (flag)
  {
    auto p = CPeople{ 10,"tommy" };
    return p;
  }
  else
  {
    auto p= CPeople{ 22,"janney" };
    return p;
  }
}

综合2和3来看,虽然返回值并未进行RVO,但是均执行的是移动构造,相对拷贝构造提高性能。

当然还有的书籍讲“函数返回的对象被其他对象引用”也会限制RVO,形如如下的代码。但是经过测试gcc和msvc中均进行了RVO,即未限制RVO,但是仍不排除部分版本的编译器会进行限制。

代码语言:javascript
复制
CPeople using_nrvo_with_ref()
{
  auto p = CPeople{ 10,"tommy" };
  auto& p_ref =p;
  std::cout<<"p_ref "<<p_ref;
  return p;
}

总结

RVO和NRVO的的核心思想是将局部对象直接构造在函数调用方的目标对象上,避免额外的对象拷贝。由于RVO(NRVO作为RVO的特例)是在编译期进行,所以具体的行为依赖于编译器,不同的编译器会有不同的行为,乃至于不同版本的编译器也会有不同的行为,为了写出通用性强的代码,请牢记可能会限制RVO的使用场景

  • 返回值类型不能是引用类型
  • 返回值不能被异常处理包围
  • 函数中不能有其他返回值
  • 函数返回的对象被其他对象引用
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-04-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员的园 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档