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 То есть я вижу, что код получается одинаковый. Можно ли утверждать, что разницы нет, что использовать? Или такой вывод ошибочный?


Ответы (0 шт):