首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >RVO应该在什么时候生效?

RVO应该在什么时候生效?
EN

Stack Overflow用户
提问于 2010-01-08 14:29:59
回答 4查看 2.1K关注 0票数 8

从下面的代码中,如果发生了RVO,我希望看到两个地址指向相同的位置,但事实并非如此(我的编译器是MS VC9.0)

代码语言:javascript
复制
#include <iostream>
#include <string>

std::string foo(std::string& s)
{
   std::cout << "address: " << (unsigned int)(&s) << std::endl;
   return s;
}

int main()
{
   std::string base = "abc";
   const std::string& s = foo(base);
   std::cout << "address: " << (unsigned int)(&s) << std::endl;
   std::cout << s << std::endl;
   return 0;
}

RVO应该在什么情况下发生?

顺便说一句,我的问题基于以下讨论:http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/

EN

回答 4

Stack Overflow用户

发布于 2010-01-08 20:31:33

RVO通常适用于返回未命名的临时对象,但不适用于返回以前创建的对象。

代码语言:javascript
复制
std::string foo() {
  return std::string("hello world"); // RVO
}

std::string foo() {
  std::string str("hello world");
  bar();
  return str; // Not RVO
}

std::string foo(std::string str) {
  return str; // Not RVO
}

一个更通用的版本是NRVO (命名返回值优化),它也适用于命名变量。

代码语言:javascript
复制
std::string foo() {
  std::string str("hello world");
  bar();
  return str; // NRVO
}

std::string foo(std::string str) {
  return str; // Not NRVO, as far as I know. The string is constructed outside the function itself, and that construction may be elided by the compiler for other reasons.
}

std::string foo(std::string str) {
  std::string ret;
  swap(ret, str);
  return ret; // NRVO. We're returning the named variable created in the function
}
票数 9
EN

Stack Overflow用户

发布于 2010-01-08 15:03:46

正确的答案是“只要编译器愿意”。这样的行为不是标准强制的(但允许的),并且它生效的确切条件因编译器和版本的不同而不同。

作为一般规则,编译器比你聪明,并且以你最大的利益工作。不要质疑它。

C++0x中的右值引用是RVO的一种手动版本。

RVO:仔细看看你的代码,你肯定误解了。因为您的参数是一个引用,所以函数的返回值不可能具有相同的地址。

票数 4
EN

Stack Overflow用户

发布于 2010-01-08 14:40:18

我不知道完整的条件,但我相信你返回的是一个参数,而不是在函数中创建的实例,这是导致你的例子出现问题的原因。

对我来说,下面显示了两者的相同地址:

代码语言:javascript
复制
#include <iostream>
#include <string>

std::string foo()
{
   std::string s("rvo!");
   std::cout << "address: " << (void *)(&s) << std::endl;
   return s;
}

int main()
{
   const std::string s = foo();
   std::cout << "address: " << (void *)(&s) << std::endl;
   std::cout << s << std::endl;
   return 0;
}

跟进darid的评论

它使用的codepad about page文档是C++的-fno-elide-构造函数。此选项的文档构成了g++手册页状态:

C++标准允许实现省略创建仅用于初始化相同类型的另一个对象的临时。指定此选项将禁用该优化,并强制G++在所有情况下调用复制构造函数。

在我的机器上,使用-fno-elide-constructors进行编译会阻止RVO,但不使用-fno-elide-constructors进行编译则会阻止RVO。

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

https://stackoverflow.com/questions/2025899

复制
相关文章

相似问题

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