Главная » Просмотр файлов » С. Мейерс - Эффективный и современный C++

С. Мейерс - Эффективный и современный C++ (1114942), страница 54

Файл №1114942 С. Мейерс - Эффективный и современный C++ (С. Мейерс - Эффективный и современный C++) 54 страницаС. Мейерс - Эффективный и современный C++ (1114942) страница 542019-05-08СтудИзба
Просмтор этого файла доступен только зарегистрированным пользователям. Но у нас супер быстрая регистрация: достаточно только электронной почты!

Текст из файла (страница 54)

Это несколько удивительно, так какони не внесли в язык никаких новых возможностей выражения идей. Все, на что способ­ны лямбда-выражения, вы в состоянии сделать вручную, разве что ценой немного боль­ших усилий по вводу с клавиатуры. Но лямбда-выражения представляют собой оченьудобное средство создания функциональных объектов, оказывающее огромное влияниена повседневную разработку программного обеспечения на С++. Без лямбда-выраже­ний алгоритмы "_i f" из STL (например, s t d : : find_i f, s t d : : remove_ i f, s t d : : count_i fи др.) обычно работают с самыми тривиальными предикатами, н о при доступностилямбда-выражений применение этих алгоритмов резко возрастает.

То же самое вернои для алгоритмов, настраиваемых с помощью пользовательской функции сравнения (на­пример, s t d : : sort , std : : nth_element, std : : lower_bound и др.). Вне STL лямбда-выра­жения позволяют быстро создавать пользовательские удалители для std : : unique_pt rи s t d : : sha red_pt r (см.

разделы 4. l и 4.2) и делают столь же простыми спецификациипредикатов для переменных условий в потоковом API (см. раздел 7.5). Помимо исполь­зования в объектах стандартной библиотеки, лямбда-выражения облегчают определениефункций обратного вызова "на лету", функций адаптации интерфейса и контекстно-за­висимых функций для разовых вызовов. Лямбда-выражения действительно делают С++более приятным языком программирования.Терминология, связанная с лямбда-выражениями, может обескуражить.

Лямбда-вы­ражение является именно тем, что написано: выражением. Это часть исходного текста.В приведенном ниже фрагменте выделенная полужирным шрифтом часть представляетсобой лямбда-выражение.std : : find_i f ( con tainer. begin ( ) , container. end ( ) ,[ ] (int val) { retшn О < val && val < 10 ; } ) ;•Замь1кание (closure) представляет собой объект времени выполнения, создаваемыйлямбда-выражением. В зависимости от режима захвата замыкания хранят копииссылок на захваченные данные. В приведенном выше вызове std : : find_i f замыка­ние представляет собой объект, передаваемый во время выполнения в std : : find_ i fв качестве третьего аргумента.•Класс замыкания (closure class) представляет собой класс, из котороrо инстанциру­ется замыкание.

Каждое лямбда-выражение заставляет компиляторы генерироватьуникальный класс замыкания. Инструкции внутри лямбда-выражения становятсявыполнимыми инструкциями функций-членов их класса замыкания.Лямбда-выражения часто используются для создания замыкания, которое применя­ется только в качестве аргумента функции. Именно этот случай представлен в приведен­ном выше примере std : : find_ if. Однако в общем случае замыкания могут копировать­ся, так что обычно можно иметь несколько замыканий типа замыкания, соответствую­щего одному лямбда-выражению. Например, в коде11 х - локальная переменнаяint х ;auto cl[ х ] ( int у ) {return хcl;auto с2с2;auto сЗ=*1111у > 5 5 ; ) ; 111111c l - копия замыкания ,сгенерированноголямбда-выражениемс2копия clсЗ - копия с2и сЗ являются копиями замыкания, порожденного лямбда-выражением.Неформально вполне приемлемо размытие границы между лямбда-выражениями, за­мыканиями и классами замыканий.

Но в последующих разделах очень часто важно раз­личать, что существует во время компиляции (лямбда-выражения и классы замыканий),что - во время выполнения (замыкания) и как они соотносятся одно с другим.cl, с26.1 . Избеrайте режимов захвата по умопчаниюВ С++ 1 1 имеются два режима захвата: по ссылке и по значению. Захват по умолчаниюпо ссылке может привести к висячим ссылкам. Захват по умолчанию по значению со­блазняет считать, что вы не подвержены этой проблеме (это не так), и думать, что вашизамыкания являются самодостаточными автономными замыканиями (но они могут и небыть таковыми).Так выглядят основные положения данного раздела. Если вы в большей степени тво­рец, чем ремесленник, вы, вероятно, захотите узнать побольше - так давайте начнемс опасности захвата по ссылке.Захват по ссылке приводит к тому, что замыкание содержит ссылку на локальнуюпеременную или на параметр, доступный в области видимости, где определено лямбда­выражение.

Если время жизни замыкания, созданного из лямбда-выражения, превышаетвремя жизни локальной переменной или параметра, ссылка в замыкании оказываетсявисячей. Предположим, например, что у нас есть контейнер с функциями фильтрации,каждая из которых принимает int и возвращает bool, указывающий, удовлетворяет липереданное значение фильтру:222Гnава 6. Лямбда-выражения11 См.

using в разделе 3 . 3 , std: : function - в 2 . 1 :using FilterContainer = std : : vector<std : : function<bool ( int ) >>;FilterContainer filters; / / Функции фильтрацииМы можем добавить фильтр для чисел, кратных 5, следующим образом:filters . ernplace_back (/ / См . ernplace_back в разделе 8 . 2[ ] ( int value ) { return value % 5 == О ; });Однако может быть так, что нам нужно вычислять делитель во время выполнения,т.е. мы не можем жестко "прошить" значение 5 в лямбда-выражении.

Поэтому добавле­ние фильтра может выглядеть следующим образом:void addDivi sorFilter ( )auto calcl = cornputeSorneValuel ( ) ;auto calc2cornputeSorneValue2 ( ) ;auto divisorcornputeDivisor ( calc l , calc2 ) ;filters . ernplace_back ( / / Опасно ! Ссылка на divi sor повиснет ![&] ( int value ) { return value % divisor == О ; }) ;==Этот код - бомба замедленного действия.

Лямбда-выражение ссылается на ло­кальную переменную divi sor, но эта переменная прекращает свое существование по­сле выхода из addDivi sorFi l te r. Этот выход осуществляется сразу после выхода изf i l ters . ernplace_back, так что добавленная в f i lters функция, по сути, является мерт­ворожденной. Применение этого фильтра ведет к неопределенному моменту практиче­ски с момента создания.Та же проблема имеет место и при явном захвате di visor по ссылке,filters . ernplace_back ([ &divisor] ( int va lue ){ return value % divisor) ;11 Опасно ! Ссылка наО ; ) // divisor все равно11 повисает !но при явном захвате проще увидеть, что жизнеспособность лямбда-выражения зависитот времени жизни di vi sor.

Кроме того, использование имени di visor напоминает намо необходимости убедиться, что di vi sor существует как минимум столько же времени,сколько и замыкание лямбда-выражения. Это более конкретное напоминание, чем обоб­щенное "убедитесь, что ничего не висит", о чем гласит конструкция [ & ] .Если вы знаете, что замыкание будет использовано немедленно (например, будучипереданным в алгоритм STL) и не будет копироваться, нет никакого риска, что ссылки,которые оно хранит, переживут локальные переменные и параметры в среде, где созда­но это лямбда-выражение. Вы могли бы утверждать, что в этом случае нет риска полу­чить висячие ссылки, а следовательно, нет причин избегать режима захвата по ссылке6.1 .Избегайте режимов захвата по умопчанию223по умолчанию.

Например, наше фильтрующее лямбда-выражение может использоватьсятолько как аргумент в алгоритме С++ 1 1 s t d : : a l l _ of, который проверяет, все ли элемен­ты диапазона удовлетворяют условию:template<typename С>void workWithContainer ( const С& container)auto calclcomputeSomeValue l ( ) ;11 Как и ранее11 Как и ранееauto calc2computeSomeVal ue2 ( ) ;auto clivisorcomputeDivisor ( ca l c l , calc2 ) ; / / Как и ранее===11 Тип элементов в контейнере :using ContElemT=typename C : : value type ;using std : : begin;using std : : end;11 Для обобщенности ;11 см.

раздел 3 . 7i f ( std: : all_of (11begin ( container ) ,11end ( container) ,11[ &] ( const ContElemT& value ){ return value % divisor) {11else {Все значенияв контейнерекратны divisor?О; ) )Да11 Как минимум одно - нетДа, все так, это безопасно, но эта безопасность довольно неустойчива.

Если выяснит­ся, что это лямбда-выражение полезно в друтих контекстах (например, как функция, до­бавленная в контейнер f i l t ers) и будет скопировано и вставлено в контекст, где этозамыкание может пережить di v i s o r, вы вновь вернетесь к повисшим ссылкам, и в выра­жении захвата не будет ничего, что напомнило бы вам о необходимости анализа временижизни di vi s or .С точки зрения долгосрочной перспективы лучше явно перечислять локальные пере­менные, от которых зависит лямбда-выражение.Кстати, возможность применения auto в спецификации параметров лямбда-выраже­ний в С++ 1 4 означает, что приведенный выше код можно записать проще при исполь­зовании С++ 1 4.

Определение псевдонима типа Con t E l emT можно убрать, а условие i fможет быть переписано следующим образом:if ( std : : all_of (begin ( container ) , end ( container ) ,[ & ] ( const auto& value )О; ) ) ){ return value % divisor==224Гла ва 6. Лямбда-выражения!/ C++ l 4Одним из способов решения нашей проблемы с локальной переменной divi s o r мо­жет быть применение режима захвата по умолчанию по значению, т.е. мы можем доба­вить лямбда-выражение к f i l t e r s следующим образом:filters . emplace_back ([=] ( iпt value ){ return value % divisor);О; }11111111Теперьdivisorн е можетзависнутьДля данного примера этого достаточно, но в общем случае захват по умолчаниюпо значению не является лекарством от висящих ссылок, как вам могло бы показаться.Проблема в том, что если вы захватите указатель по значению, то скопируете его в замы­кания, возникающие из лямбда-выражения, но не сможете предотвратить освобождениеобъекта, на который он указывает (и соответственно, повисания), внешним кодом."Этого не может случиться! - возразите вы.

Характеристики

Тип файла
PDF-файл
Размер
12,67 Mb
Тип материала
Высшее учебное заведение

Список файлов книги

Свежие статьи
Популярно сейчас
Почему делать на заказ в разы дороже, чем купить готовую учебную работу на СтудИзбе? Наши учебные работы продаются каждый год, тогда как большинство заказов выполняются с нуля. Найдите подходящий учебный материал на СтудИзбе!
Ответы на популярные вопросы
Да! Наши авторы собирают и выкладывают те работы, которые сдаются в Вашем учебном заведении ежегодно и уже проверены преподавателями.
Да! У нас любой человек может выложить любую учебную работу и зарабатывать на её продажах! Но каждый учебный материал публикуется только после тщательной проверки администрацией.
Вернём деньги! А если быть более точными, то автору даётся немного времени на исправление, а если не исправит или выйдет время, то вернём деньги в полном объёме!
Да! На равне с готовыми студенческими работами у нас продаются услуги. Цены на услуги видны сразу, то есть Вам нужно только указать параметры и сразу можно оплачивать.
Отзывы студентов
Ставлю 10/10
Все нравится, очень удобный сайт, помогает в учебе. Кроме этого, можно заработать самому, выставляя готовые учебные материалы на продажу здесь. Рейтинги и отзывы на преподавателей очень помогают сориентироваться в начале нового семестра. Спасибо за такую функцию. Ставлю максимальную оценку.
Лучшая платформа для успешной сдачи сессии
Познакомился со СтудИзбой благодаря своему другу, очень нравится интерфейс, количество доступных файлов, цена, в общем, все прекрасно. Даже сам продаю какие-то свои работы.
Студизба ван лав ❤
Очень офигенный сайт для студентов. Много полезных учебных материалов. Пользуюсь студизбой с октября 2021 года. Серьёзных нареканий нет. Хотелось бы, что бы ввели подписочную модель и сделали материалы дешевле 300 рублей в рамках подписки бесплатными.
Отличный сайт
Лично меня всё устраивает - и покупка, и продажа; и цены, и возможность предпросмотра куска файла, и обилие бесплатных файлов (в подборках по авторам, читай, ВУЗам и факультетам). Есть определённые баги, но всё решаемо, да и администраторы реагируют в течение суток.
Маленький отзыв о большом помощнике!
Студизба спасает в те моменты, когда сроки горят, а работ накопилось достаточно. Довольно удобный сайт с простой навигацией и огромным количеством материалов.
Студ. Изба как крупнейший сборник работ для студентов
Тут дофига бывает всего полезного. Печально, что бывают предметы по которым даже одного бесплатного решения нет, но это скорее вопрос к студентам. В остальном всё здорово.
Спасательный островок
Если уже не успеваешь разобраться или застрял на каком-то задание поможет тебе быстро и недорого решить твою проблему.
Всё и так отлично
Всё очень удобно. Особенно круто, что есть система бонусов и можно выводить остатки денег. Очень много качественных бесплатных файлов.
Отзыв о системе "Студизба"
Отличная платформа для распространения работ, востребованных студентами. Хорошо налаженная и качественная работа сайта, огромная база заданий и аудитория.
Отличный помощник
Отличный сайт с кучей полезных файлов, позволяющий найти много методичек / учебников / отзывов о вузах и преподователях.
Отлично помогает студентам в любой момент для решения трудных и незамедлительных задач
Хотелось бы больше конкретной информации о преподавателях. А так в принципе хороший сайт, всегда им пользуюсь и ни разу не было желания прекратить. Хороший сайт для помощи студентам, удобный и приятный интерфейс. Из недостатков можно выделить только отсутствия небольшого количества файлов.
Спасибо за шикарный сайт
Великолепный сайт на котором студент за не большие деньги может найти помощь с дз, проектами курсовыми, лабораторными, а также узнать отзывы на преподавателей и бесплатно скачать пособия.
Популярные преподаватели
Добавляйте материалы
и зарабатывайте!
Продажи идут автоматически
6418
Авторов
на СтудИзбе
307
Средний доход
с одного платного файла
Обучение Подробнее