I'm observing a situation when depending on -std=c++11
or -std=c++14/1z
flags gcc
(both 5.4 and 7.3) either (my understanding) applies RVO or does not in the case when there are parentheses around return statement expression. clang
seems to emit same code that uses RVO in both cases.
Please, consider the following:
#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;
}
For g++ -std=c++11 -O3 -Wall -Wextra -Wpedantic
the output is:
ctor
ctor
--- f1 ---
ctor
move =
dtor
--- f2 ---
ctor
move =
dtor
---
dtor
dtor
For g++ -std=c++14 -O3 -Wall -Wextra -Wpedantic
the output is:
ctor
ctor
--- f1 ---
ctor
move =
dtor
--- f2 ---
ctor
move ctor
dtor
move =
dtor
---
dtor
dtor
Here is the relevant assembler for f1()
and f2()
(see it on 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
And the question is, basically, what's going on? Why does RVO (?) breaks on return statement parentheses in gcc -std=c++14/1z
? I know about decltype(auto) x4d = (i); // decltype(x4d) is int&
situation, but this shouldn't be the case here.
The implications are kind of grave, considering how much code might be using parentheses and be switching from c++11 to c++14 compilation flags.
Thanks!
Aucun commentaire:
Enregistrer un commentaire