The difference between f(A&&) and f(A)
Let us consider the following code:
#include
#include
class A {
int a;
public:
A(A&& a) {}
A(int _a) : a(_a){}
int f(A a) {
std::cout << a.a << std::endl;
}
};
int main()
{
A a(1);
a.f(A(2));
return 0;
}
It generates the following code:
std::piecewise_construct:
.zero 1
A::A(int):
pushq %rbp
movq %rsp, %rbp
movq %rdi, -8(%rbp)
movl %esi, -12(%rbp)
movq -8(%rbp), %rax
movl -12(%rbp), %edx
movl %edx, (%rax)
nop
popq %rbp
ret
A::f(A):
pushq %rbp
movq %rsp, %rbp
subq $16, %rsp
movq %rdi, -8(%rbp)
movq %rsi, -16(%rbp)
movq -16(%rbp), %rax
movl (%rax), %eax
movl %eax, %esi
movl std::cout, %edi
call std::basic_ostream >::operator<<(int)
movl std::basic_ostream >& std::endl >(std::basic_ostream >&), %esi
movq %rax, %rdi
call std::basic_ostream >::operator<<(std::basic_ostream >& (*)(std::basic_ostream >&))
nop
leave
ret
main:
pushq %rbp
movq %rsp, %rbp
subq $32, %rsp
leaq -32(%rbp), %rax
movl $1, %esi
movq %rax, %rdi
call A::A(int)
leaq -16(%rbp), %rax
movl $2, %esi
movq %rax, %rdi
call A::A(int)
leaq -16(%rbp), %rdx
leaq -32(%rbp), %rax
movq %rdx, %rsi
movq %rax, %rdi
call A::f(A)
movl $0, %eax
leave
ret
__static_initialization_and_destruction_0(int, int):
pushq %rbp
movq %rsp, %rbp
subq $16, %rsp
movl %edi, -4(%rbp)
movl %esi, -8(%rbp)
cmpl $1, -4(%rbp)
jne .L7
cmpl $65535, -8(%rbp)
jne .L7
movl std::__ioinit, %edi
call std::ios_base::Init::Init()
movl $__dso_handle, %edx
movl std::__ioinit, %esi
movl std::ios_base::Init::~Init(), %edi
call __cxa_atexit
.L7:
nop
leave
ret
pushq %rbp
movq %rsp, %rbp
movl $65535, %esi
movl $1, %edi
call __static_initialization_and_destruction_0(int, int)
popq %rbp
ret
#include
#include
class A {
int a;
public:
A(A&& a) {}
A(int _a) : a(_a){}
int f(A a) {
std::cout << a.a << std::endl;
}
};
int main()
{
A a(1);
a.f(A(2));
return 0;
}
It generates the following code:
std::piecewise_construct:
.zero 1
A::A(int):
pushq %rbp
movq %rsp, %rbp
movq %rdi, -8(%rbp)
movl %esi, -12(%rbp)
movq -8(%rbp), %rax
movl -12(%rbp), %edx
movl %edx, (%rax)
nop
popq %rbp
ret
A::f(A):
pushq %rbp
movq %rsp, %rbp
subq $16, %rsp
movq %rdi, -8(%rbp)
movq %rsi, -16(%rbp)
movq -16(%rbp), %rax
movl (%rax), %eax
movl %eax, %esi
movl std::cout, %edi
call std::basic_ostream
movl std::basic_ostream
movq %rax, %rdi
call std::basic_ostream
nop
leave
ret
main:
pushq %rbp
movq %rsp, %rbp
subq $32, %rsp
leaq -32(%rbp), %rax
movl $1, %esi
movq %rax, %rdi
call A::A(int)
leaq -16(%rbp), %rax
movl $2, %esi
movq %rax, %rdi
call A::A(int)
leaq -16(%rbp), %rdx
leaq -32(%rbp), %rax
movq %rdx, %rsi
movq %rax, %rdi
call A::f(A)
movl $0, %eax
leave
ret
__static_initialization_and_destruction_0(int, int):
pushq %rbp
movq %rsp, %rbp
subq $16, %rsp
movl %edi, -4(%rbp)
movl %esi, -8(%rbp)
cmpl $1, -4(%rbp)
jne .L7
cmpl $65535, -8(%rbp)
jne .L7
movl std::__ioinit, %edi
call std::ios_base::Init::Init()
movl $__dso_handle, %edx
movl std::__ioinit, %esi
movl std::ios_base::Init::~Init(), %edi
call __cxa_atexit
.L7:
nop
leave
ret
pushq %rbp
movq %rsp, %rbp
movl $65535, %esi
movl $1, %edi
call __static_initialization_and_destruction_0(int, int)
popq %rbp
ret
Let's slightly change the code:
#include
#include
class A {
int a;
public:
A(A&& a) {}
A(int _a) : a(_a){}
int f(A&& a) {
std::cout << a.a << std::endl;
}
};
int main()
{
A a(1);
a.f(std::move(A(2)));
return 0;
}
It then generates the following snippet:
std::piecewise_construct:
.zero 1
A::A(int):
pushq %rbp
movq %rsp, %rbp
movq %rdi, -8(%rbp)
movl %esi, -12(%rbp)
movq -8(%rbp), %rax
movl -12(%rbp), %edx
movl %edx, (%rax)
nop
popq %rbp
ret
A::f(A&&):
pushq %rbp
movq %rsp, %rbp
subq $16, %rsp
movq %rdi, -8(%rbp)
movq %rsi, -16(%rbp)
movq -16(%rbp), %rax
movl (%rax), %eax
movl %eax, %esi
movl std::cout, %edi
call std::basic_ostream >::operator<<(int)
movl std::basic_ostream >& std::endl >(std::basic_ostream >&), %esi
movq %rax, %rdi
call std::basic_ostream >::operator<<(std::basic_ostream >& (*)(std::basic_ostream >&))
nop
leave
ret
std::remove_reference::type&& std::move(A&&):
pushq %rbp
movq %rsp, %rbp
movq %rdi, -8(%rbp)
movq -8(%rbp), %rax
popq %rbp
ret
main:
pushq %rbp
movq %rsp, %rbp
subq $32, %rsp
leaq -32(%rbp), %rax
movl $1, %esi
movq %rax, %rdi
call A::A(int)
leaq -16(%rbp), %rax
movl $2, %esi
movq %rax, %rdi
call A::A(int)
leaq -16(%rbp), %rax
movq %rax, %rdi
call std::remove_reference::type&& std::move(A&&)
movq %rax, %rdx
leaq -32(%rbp), %rax
movq %rdx, %rsi
movq %rax, %rdi
call A::f(A&&)
movl $0, %eax
leave
ret
__static_initialization_and_destruction_0(int, int):
pushq %rbp
movq %rsp, %rbp
subq $16, %rsp
movl %edi, -4(%rbp)
movl %esi, -8(%rbp)
cmpl $1, -4(%rbp)
jne .L9
cmpl $65535, -8(%rbp)
jne .L9
movl std::__ioinit, %edi
call std::ios_base::Init::Init()
movl $__dso_handle, %edx
movl std::__ioinit, %esi
movl std::ios_base::Init::~Init(), %edi
call __cxa_atexit
.L9:
nop
leave
ret
pushq %rbp
movq %rsp, %rbp
movl $65535, %esi
movl $1, %edi
call __static_initialization_and_destruction_0(int, int)
popq %rbp
ret
#include
#include
class A {
int a;
public:
A(A&& a) {}
A(int _a) : a(_a){}
int f(A&& a) {
std::cout << a.a << std::endl;
}
};
int main()
{
A a(1);
a.f(std::move(A(2)));
return 0;
}
It then generates the following snippet:
std::piecewise_construct:
.zero 1
A::A(int):
pushq %rbp
movq %rsp, %rbp
movq %rdi, -8(%rbp)
movl %esi, -12(%rbp)
movq -8(%rbp), %rax
movl -12(%rbp), %edx
movl %edx, (%rax)
nop
popq %rbp
ret
A::f(A&&):
pushq %rbp
movq %rsp, %rbp
subq $16, %rsp
movq %rdi, -8(%rbp)
movq %rsi, -16(%rbp)
movq -16(%rbp), %rax
movl (%rax), %eax
movl %eax, %esi
movl std::cout, %edi
call std::basic_ostream
movl std::basic_ostream
movq %rax, %rdi
call std::basic_ostream
nop
leave
ret
std::remove_reference::type&& std::move(A&&):
pushq %rbp
movq %rsp, %rbp
movq %rdi, -8(%rbp)
movq -8(%rbp), %rax
popq %rbp
ret
main:
pushq %rbp
movq %rsp, %rbp
subq $32, %rsp
leaq -32(%rbp), %rax
movl $1, %esi
movq %rax, %rdi
call A::A(int)
leaq -16(%rbp), %rax
movl $2, %esi
movq %rax, %rdi
call A::A(int)
leaq -16(%rbp), %rax
movq %rax, %rdi
call std::remove_reference::type&& std::move(A&&)
movq %rax, %rdx
leaq -32(%rbp), %rax
movq %rdx, %rsi
movq %rax, %rdi
call A::f(A&&)
movl $0, %eax
leave
ret
__static_initialization_and_destruction_0(int, int):
pushq %rbp
movq %rsp, %rbp
subq $16, %rsp
movl %edi, -4(%rbp)
movl %esi, -8(%rbp)
cmpl $1, -4(%rbp)
jne .L9
cmpl $65535, -8(%rbp)
jne .L9
movl std::__ioinit, %edi
call std::ios_base::Init::Init()
movl $__dso_handle, %edx
movl std::__ioinit, %esi
movl std::ios_base::Init::~Init(), %edi
call __cxa_atexit
.L9:
nop
leave
ret
pushq %rbp
movq %rsp, %rbp
movl $65535, %esi
movl $1, %edi
call __static_initialization_and_destruction_0(int, int)
popq %rbp
ret
So here we see the difference, the second case has more code:
std::remove_reference::type&& std::move(A&&):
pushq %rbp
movq %rsp, %rbp
movq %rdi, -8(%rbp)
movq -8(%rbp), %rax
popq %rbp
ret
...
Comments