Виталий Евгеньевич Ткаченко - Обратные вызовы в C++ стр 14.

Книгу можно купить на ЛитРес.
Всего за 0.01 руб. Купить полную версию
Шрифт
Фон

#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, в котором производится вызов функции (Листинг 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 это локальная неименованная функция, которая, подобно обычной функции, может принимать входные параметры и возвращать результат. Особенностью лямбда-выражений, отличающих их от обычных функций, является возможность захвата переменных.

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


Рис. 15. Реализация обратного вызова с помощью лямбда-выражения


2.5.2. Инициатор

Как хранить и передавать лямбда-выражение как аргумент? Если оно не захватывает переменные, то стандарт допускает неявное преобразование лямбда-выражения к указателю на функцию. В этом случае реализация инициатора полностью совпадает с рассмотренной в 2.1. Однако использование лямбда-выражений без захвата переменных не дает никакого преимущества по сравнению с обычной функцией, использовать их в таком виде не имеет смысла.

Другое дело, когда лямбда-выражение осуществляет захват переменных, в этом случае мы получаем мощный и гибкий инструмент управления контекстом. Однако использование таких выражений в качестве аргумента вызывает определенные сложности. Связано это с тем, что тип лямбда-выражения является анонимным. Как следствие, имя типа нам неизвестно, и мы не можем просто объявить переменную нужного типа и присвоить ей лямбда-выражение, как это происходит, например, с указателями или классами. Решается указанная проблема с помощью шаблонов, что будет рассмотрено позже в соответствующих главах. Забегая вперед, отметим, что для хранения лямбда-выражений можно объявлять шаблон с параметром типом лямбда-выражения (п. 4.4.2) либо использовать специальные классы библиотеки STL (п. 4.6.1).

Ваша оценка очень важна

0
Шрифт
Фон

Помогите Вашим друзьям узнать о библиотеке

Скачать книгу

Если нет возможности читать онлайн, скачайте книгу файлом для электронной книжки и читайте офлайн.

fb2.zip txt txt.zip rtf.zip a4.pdf a6.pdf mobi.prc epub ios.epub fb3