【问题标题】:GCC C++11/14 and RVO in return statement with parenthesesGCC C++11/14 和 RVO 在带括号的 return 语句中
【发布时间】:2018-09-30 13:51:36
【问题描述】:

我观察到一种情况,依赖于 -std=c++11 或 -std=c++14/1z 标志 gcc(5.4 和 7.3)要么(我的理解)适用 RVO,要么在 return 语句表达式周围有括号的情况下不适用. clang 似乎在这两种情况下都会发出使用 RVO 的相同代码。

请考虑以下几点:

#include <iostream>

class C {
  public:
    C(){ std::cout << "ctor" << std::endl; }
    C(C const &){ std::cout << "copy ctor" << std::endl; }
    C(C &&){ std::cout << "move ctor" << std::endl; }
    C & operator=(C const &){ std::cout << "copy =" << std::endl; return *this; }
    C & operator=(C &&){ std::cout << "move =" << std::endl; return *this; }
    ~C() { std::cout << "dtor" << std::endl; }
};

C f1() { C c; return c; }

C f2() { C c; return (c); } // <--- added parentheses;

int main() {
  C c1{}, c2{};

  std::cout << "--- f1 ---" << std::endl;
  c1 = f1();
  std::cout << "--- f2 ---" << std::endl;
  c2 = f2();
  std::cout << "---" << std::endl;
}

对于g++ -std=c++11 -O3 -Wall -Wextra -Wpedantic,输出为:

ctor
ctor
--- f1 ---
ctor
move =
dtor
--- f2 ---
ctor
move =
dtor
---
dtor
dtor

对于g++ -std=c++14 -O3 -Wall -Wextra -Wpedantic,输出为:

ctor
ctor
--- f1 ---
ctor
move =
dtor
--- f2 ---
ctor
move ctor
dtor
move =
dtor
---
dtor
dtor

这是f1() 和f2() 的相关汇编程序(参见godbolt.org):

f1():
  push rbp
  mov rbp, rsp
  sub rsp, 16
  mov QWORD PTR [rbp-8], rdi
  mov rax, QWORD PTR [rbp-8]
  mov rdi, rax
  call C::C()
  nop
  mov rax, QWORD PTR [rbp-8]
  leave
  ret
f2():
  push rbp
  mov rbp, rsp
  push rbx
  sub rsp, 40
  mov QWORD PTR [rbp-40], rdi
  lea rax, [rbp-17]
  mov rdi, rax
  call C::C()
  lea rdx, [rbp-17]
  mov rax, QWORD PTR [rbp-40]
  mov rsi, rdx
  mov rdi, rax
  call C::C(C&&)
  nop
  lea rax, [rbp-17]
  mov rdi, rax
  call C::~C()
  jmp .L12
  mov rbx, rax
  lea rax, [rbp-17]
  mov rdi, rax
  call C::~C()
  mov rax, rbx
  mov rdi, rax
  call _Unwind_Resume

问题是,基本上,发生了什么?为什么 RVO (?) 在 gcc -std=c++14/1z 中的 return 语句括号上中断?我知道decltype(auto) x4d = (i); // decltype(x4d) is int&amp; 的情况,但这里不应该是这种情况。

考虑到有多少代码可能使用括号并从 c++11 切换到 c++14 编译标志,其含义有点严重。

谢谢!

【问题讨论】:

    标签: c++11 gcc return c++14 parentheses


    【解决方案1】:

    根据 C++ 标准,return c; 和 return (c); 之间的行为没有区别。 C++11、14、17都说下括号表达式的定义:

    括号里的表达式可以用在与括号里的表达式完全相同的上下文中,并且具有相同的含义,除非另有说明。

    并且在规范的复制省略部分没有“另有说明”。


    由于复制省略是可选的,gcc 这样做并没有违反标准。但也许它可以被认为是实施质量错误。

    没有理由写 return (c); 而不是 return c; ,因此您可以通过 grepping return ( 的代码库并删除多余的括号来安全地处理问题。

    【讨论】:

      猜你喜欢
      • 2014-07-30
      • 1970-01-01
      • 1970-01-01
      • 2011-06-26
      • 2017-01-22
      • 2014-11-24
      • 2011-06-13
      相关资源
      最近更新 更多