【发布时间】: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& 的情况,但这里不应该是这种情况。
考虑到有多少代码可能使用括号并从 c++11 切换到 c++14 编译标志,其含义有点严重。
谢谢!
【问题讨论】:
标签: c++11 gcc return c++14 parentheses