std::bind vs lambda
Хочу разобраться - что лучше в пдане производительности и генерируемого кода. Мейерс писал, что лябды начиная с 14 стандарта как минимум не хуже в плане функциональности. Я решил это проверить и написал небольшой класс:
#include <functional>
struct foo {
int func_foo(int a, int b) {
return a+b;
};
std::function<int(int, int)> m_func;
void create_func() {
#if BIND
m_func = std::bind(&foo::func_foo,
this,
std::placeholders::_1,
std::placeholders::_2);
#else
m_func = [](int a, int b) {
return a+b;
};
#endif
};
};
int main()
{
foo f;
int a = 1, b = 3;
f.create_func();
volatile int c = 1;
c += f.m_func(a,b);
}
Результат асм-кода с std::bind
std::_Function_handler<int (int, int), foo::create_func()::{lambda(int, int)#1}>::_M_invoke(std::_Any_data const&, int&&, std::_Any_data const&):
mov eax, DWORD PTR [rdx]
add eax, DWORD PTR [rsi]
ret
std::_Function_handler<int (int, int), foo::create_func()::{lambda(int, int)#1}>::_M_manager(std::_Any_data&, std::_Function_handler<int (int, int), foo::create_func()::{lambda(int, int)#1}> const&, std::_Manager_operation):
test edx, edx
je .L4
cmp edx, 1
jne .L6
mov QWORD PTR [rdi], rsi
.L6:
xor eax, eax
ret
.L4:
mov QWORD PTR [rdi], OFFSET FLAT:typeinfo for foo::create_func()::{lambda(int, int)#1}
xor eax, eax
ret
main:
sub rsp, 88
mov eax, OFFSET FLAT:std::_Function_handler<int (int, int), foo::create_func()::{lambda(int, int)#1}>::_M_manager(std::_Any_data&, std::_Function_handler<int (int, int), foo::create_func()::{lambda(int, int)#1}> const&, std::_Manager_operation)
movdqa xmm1, XMMWORD PTR [rsp+48]
movq xmm0, rax
lea rdx, [rsp+48]
lea rsi, [rsp+12]
movhps xmm0, QWORD PTR .LC0[rip]
lea rdi, [rsp+16]
mov DWORD PTR [rsp+8], 1
movaps XMMWORD PTR [rsp+16], xmm1
movaps XMMWORD PTR [rsp+32], xmm0
mov DWORD PTR [rsp+12], 1
mov DWORD PTR [rsp+48], 3
call std::_Function_handler<int (int, int), foo::create_func()::{lambda(int, int)#1}>::_M_invoke(std::_Any_data const&, int&&, std::_Any_data const&)
lea rsi, [rsp+16]
mov edx, 3
mov r8d, eax
mov eax, DWORD PTR [rsp+8]
mov rdi, rsi
add eax, r8d
mov DWORD PTR [rsp+8], eax
call std::_Function_handler<int (int, int), foo::create_func()::{lambda(int, int)#1}>::_M_manager(std::_Any_data&, std::_Function_handler<int (int, int), foo::create_func()::{lambda(int, int)#1}> const&, std::_Manager_operation)
xor eax, eax
add rsp, 88
ret
typeinfo name for foo::create_func()::{lambda(int, int)#1}:
.string "ZN3foo11create_funcEvEUliiE_"
typeinfo for foo::create_func()::{lambda(int, int)#1}:
.quad vtable for __cxxabiv1::__class_type_info+16
.quad typeinfo name for foo::create_func()::{lambda(int, int)#1}
.LC0:
.quad std::_Function_handler<int (int, int), foo::create_func()::{lambda(int, int)#1}>::_M_invoke(std::_Any_data const&, int&&, std::_Any_data const&)
Результат с лямбдой:
std::_Function_handler<int (int, int), foo::create_func()::{lambda(int, int)#1}>::_M_invoke(std::_Any_data const&, int&&, std::_Any_data const&):
mov eax, DWORD PTR [rdx]
add eax, DWORD PTR [rsi]
ret
std::_Function_handler<int (int, int), foo::create_func()::{lambda(int, int)#1}>::_M_manager(std::_Any_data&, std::_Function_handler<int (int, int), foo::create_func()::{lambda(int, int)#1}> const&, std::_Manager_operation):
test edx, edx
je .L4
cmp edx, 1
jne .L6
mov QWORD PTR [rdi], rsi
.L6:
xor eax, eax
ret
.L4:
mov QWORD PTR [rdi], OFFSET FLAT:typeinfo for foo::create_func()::{lambda(int, int)#1}
xor eax, eax
ret
main:
sub rsp, 88
mov eax, OFFSET FLAT:std::_Function_handler<int (int, int), foo::create_func()::{lambda(int, int)#1}>::_M_manager(std::_Any_data&, std::_Function_handler<int (int, int), foo::create_func()::{lambda(int, int)#1}> const&, std::_Manager_operation)
movdqa xmm1, XMMWORD PTR [rsp+48]
movq xmm0, rax
lea rdx, [rsp+48]
lea rsi, [rsp+12]
movhps xmm0, QWORD PTR .LC0[rip]
lea rdi, [rsp+16]
mov DWORD PTR [rsp+8], 1
movaps XMMWORD PTR [rsp+16], xmm1
movaps XMMWORD PTR [rsp+32], xmm0
mov DWORD PTR [rsp+12], 1
mov DWORD PTR [rsp+48], 3
call std::_Function_handler<int (int, int), foo::create_func()::{lambda(int, int)#1}>::_M_invoke(std::_Any_data const&, int&&, std::_Any_data const&)
lea rsi, [rsp+16]
mov edx, 3
mov r8d, eax
mov eax, DWORD PTR [rsp+8]
mov rdi, rsi
add eax, r8d
mov DWORD PTR [rsp+8], eax
call std::_Function_handler<int (int, int), foo::create_func()::{lambda(int, int)#1}>::_M_manager(std::_Any_data&, std::_Function_handler<int (int, int), foo::create_func()::{lambda(int, int)#1}> const&, std::_Manager_operation)
xor eax, eax
add rsp, 88
ret
typeinfo name for foo::create_func()::{lambda(int, int)#1}:
.string "ZN3foo11create_funcEvEUliiE_"
typeinfo for foo::create_func()::{lambda(int, int)#1}:
.quad vtable for __cxxabiv1::__class_type_info+16
.quad typeinfo name for foo::create_func()::{lambda(int, int)#1}
.LC0:
.quad std::_Function_handler<int (int, int), foo::create_func()::{lambda(int, int)#1}>::_M_invoke(std::_Any_data const&, int&&, std::_Any_data const&)
Использовал последний gcc/clang -std=c++17/11 -O3/2/1 https://godbolt.org/z/cYxPY3 То есть я вижу, что код получается одинаковый. Можно ли утверждать, что разницы нет, что использовать? Или такой вывод ошибочный?