RVO 应何时启动?

发布于 2024-08-17 12:51:36 字数 718 浏览 8 评论 0原文

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

#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/

From the following code, If RVO has happened, I expect to see the 2 addresses pointing to the same location, however this is not the case (my compiler is MS VC9.0)

#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;
}

Under what conditions should RVO be happening?

btw, I'm basing my question on the following discussion: http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

五里雾 2024-08-24 12:51:36

RVO 通常适用于返回未命名临时对象的情况,但如果返回先前创建的对象则不适用。

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(命名返回值优化),它也适用于命名变量。

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
}

RVO generally applies when you return an unnamed temporary, but not if you return a previously created object.

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
}

A more general version is NRVO (Named return value optimization), which also works on named variables.

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
}
楠木可依 2024-08-24 12:51:36

正确的答案是“只要编译器愿意”。标准并未强制(但允许)这种行为,并且其启动的确切条件因编译器和版本而异。

一般来说,编译器比你更聪明,并且会为你的最大利益而工作。不要质疑它。

C++0x 中的右值引用有点像 RVO 的手动版本。

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

The correct answer is "whenever the compiler pleases". Such behavior is not mandated (but is allowed) by the standard, and the exact conditions where it kicks in varies from compiler to compiler and version to version.

As a general rule, the compiler is smarter than you, and working in your best interest. Do not question it.

rvalue references in C++0x are sort of a manual version of RVO.

Edit: Looking closer at your code, you're definately misunderstanding RVO. Because your parameter is a reference, there is no way the return value of the function could have the same address.

┼── 2024-08-24 12:51:36

我不知道完整的条件,但我相信您返回的是参数而不是函数中创建的实例,这一事实导致了示例中的问题。

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

#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 的评论

键盘关于页面 记录了它使用 C++ 的 -fno-elide-constructors 。该选项的文档形成了 g++ 手册页状态:

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

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

I don't know the full conditions, but I believe the fact that you are returning a parameter and not an instance created in the function is causing the problem in your example.

For me, the following showed the same address for both:

#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;
}

Follow up to darid's comment

The codepad about page documents that for it use's the -fno-elide-constructors for C++. The documentation for this option form the g++ man page state:

The C++ standard allows an implementation to omit creating a
temporary which is only used to initialize another object of the
same type. Specifying this option disables that optimization, and
forces G++ to call the copy constructor in all cases.

On my machine, compiling with -fno-elide-constructors prevents RVO, but compiling without allows it.

天荒地未老 2024-08-24 12:51:36

您似乎误解了 RVO,请尝试这个示例(实际上是 NRVO)

std::string foo(const char* const s)
{
    std::string out(s);
    std::cout << "address: " << (void*)(&out) << std::endl;
    return out;
}

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

You seem to misunderstand RVO, try this example (actually NRVO):

std::string foo(const char* const s)
{
    std::string out(s);
    std::cout << "address: " << (void*)(&out) << std::endl;
    return out;
}

int main()
{
   std::string s = foo("abc");
   std::cout << "address: " << (void*)(&s) << std::endl;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文