Оценить:
 Рейтинг: 0

Обратные вызовы в C++

Год написания книги
2021
<< 1 ... 7 8 9 10 11 12 13 >>
На страницу:
11 из 13
Настройки чтения
Размер шрифта
Высота строк
Поля

Поясним сказанное на примере. Напишем маленькую простую программу, которая считывает из консоли два числа, складывает их и результат выводит на экран (Листинг 19).

Листинг 19. Маленькая простая программа

#include <iostream>

int Calculate(int a, int b)

{

return a + b;

}

int main()

{

int a, b;

std::cin >> a >> b;

int result = Calculate(a, b);

std::cout << result;

}

Откомпилируем код с выключенной оптимизацией и запустим на выполнение. Посмотрим дизассемблерный участок кода [11 - Этот код получен с помощью компилятора Microsoft Visual studio версии 19.23.28106.4. Другие компиляторы могут генерировать отличающийся код, но принцип останется прежним.], в котором производится вызов функции (Листинг 20):

Листинг 20. Дизассемблерный код с выключенной оптимизацией:

int Calculate(int a, int b)

{

00007FF6DA741005  and         al,8               // 1

return a + b;

00007FF6DA741008  mov         eax,dword ptr [b]  // 2

00007FF6DA74100C  mov         ecx,dword ptr [a]  // 3

00007FF6DA741010  add          ecx,eax           // 4

00007FF6DA741012  mov         eax,ecx            // 5

}

00007FF6DA741014  ret                            // 6

int main()

{

…….

int result = Calculate(a, b);

00007FF6DA741053  mov         edx,dword ptr [b]             // 7

00007FF6DA741057  mov         ecx,dword ptr [a]             // 8

00007FF6DA74105B  call           Calculate (07FF6DA741000h) // 9

00007FF6DA741060  mov         dword ptr [result],eax        // 10

…….

В строках 7 и 8 введенные значения a и b сохраняются в регистрах. В строке 9 выполняется вызов функции. В строке 1 выполняется обнуление результата, в строках 2 и 3 переданные значения копируются в регистры, в строке 4 выполняется сложение, в строке 5 результат копируется обратно в регистр, в строке 6 выполняется выход из функции, в строке 10 результат вычисления функции копируется в переменную результата.

Теперь включим оптимизацию, откомпилируем и посмотрим на код (Листинг 21):

Листинг 21. Дизассемблерный код с включенной оптимизацией

int main()

{

…….

int result = Calculate(a, b);

00007FF7D5B11033  mov         edx,dword ptr [b]

00007FF7D5B11037  add          edx,dword ptr [a]  

Как видим, для вычислений у нас всего две операции: запись в регистр значения b и добавление к нему значения a. Код встроен в поток выполнения, вызов функции не производится. Ощутимая разница, не правда ли?

2.5. Лямбда-выражение

2.5.1. Концепция

Лямбда-выражение[12 - В литературе можно встретить термин «лямбда-функция», но в стандарте С++ он именуется как “lambda-expression”, что в переводе означает «лямбда-выражение».] – это локальная неименованная функция, которая, подобно обычной функции, может принимать входные параметры и возвращать результат. Особенностью лямбда-выражений, отличающих их от обычных функций, является возможность захвата переменных.

Графическое изображение обратного вызова с помощью лямбда-выражения представлено на Рис. 15. Исполнитель реализуется в виде какой-либо исполняемой функции, в качестве которой могут выступать глобальная функция, статический метод класса, метод-член класса, перегруженный оператор. Код обратного вызова упаковывается в лямбда-выражение, в качестве контекста выступают захваченные переменные. При настройке лямбда-выражение как аргумент сохраняется в инициаторе. Инициатор осуществляет обратный вызов посредством вызова хранимого выражения, передавая ему требуемую информацию. Контекст здесь передавать не нужно, поскольку внутри тела лямбда-выражения доступны все захваченные переменные.

Рис. 15. Реализация обратного вызова с помощью лямбда-выражения.
<< 1 ... 7 8 9 10 11 12 13 >>
На страницу:
11 из 13