Эффективный и современный С++. 42 рекомендации по использованию С++11 и С++14 - [18]

Шрифт
Интервал

:

>auto derefLess =           // Функция сравнения в С++14,

> [](const auto& p1,        // для значений, на которые

>    const auto& p2)        // указывает что угодно

>    { return *p1 < *p2; }; // указателеобразное

Несмотря на всю крутость вы, вероятно, думаете, что можно обойтись и без >auto для объявления переменной, которая хранит лямбда-выражение, поскольку мы можем использовать объект >std::function. Это так, можем, но, возможно, это не то, что вы на самом деле подразумеваете. А может быть, вы сейчас думаете “А что это такое — объект >std::function?” Давайте разбираться.

>std::function — шаблон стандартной библиотеки С++11, который обобщает идею указателя на функцию. В то время как указатели на функции могут указывать только на функции, объект >std::function может ссылаться на любой вызываемый объект, т.e. на все, что может быть вызвано как функция. Так же как при создании указателя на функцию вы должны указать тип функции, на которую указываете (т.e. сигнатуру функции, на которую хотите указать), вы должны указать тип функции, на которую будет ссылаться создаваемый объект >std::function. Это делается с помощью параметра шаблона >std::function. Например, для объявления объекта >std::function с именем >func, который может ссылаться на любой вызываемый объект, действующий так, как если бы его сигнатура была

>bool(const std::unique_ptr&, // Сигнатура C++11 для

>     const std::unique_ptr&) // функции сравнения

>                                     // std::unique_ptr

следует написать следующее:

>std::function<bool(const std::unique_ptr&,

>                   const std::unique_ptr&)> func;

Поскольку лямбда-выражения дают вызываемые объекты, замыкания могут храниться в объектах >std::function. Это означает, что можно объявить С++11-версию >derefUPLess без применения >auto следующим образом:

>std::function&,

>                   const std::unique_ptr&)>

> derefUPLess = [](const std::unique_ptr& p1,

>                  const std::unique_ptr& p2)

>                  { return *p1 < *p2; };

Важно понимать, что, даже если оставить в стороне синтаксическую многословность и необходимость повторения типов параметров, использование >std::function — не то же самое, что использование >auto. Переменная, объявленная с использованием >auto и хранящая замыкание, имеет тот же тип, что и замыкание, и как таковая использует только то количество памяти, которое требуется замыканию. Тип переменной, объявленной как >std::function и хранящей замыкание, представляет собой конкретизацию шаблона >std::function, которая имеет фиксированный размер для каждой заданной сигнатуры. Этот размер может быть не адекватным для замыкания, которое требуется хранить, и в этом случае конструктор >std::function будет выделять для хранения замыкания динамическую память. В результате объект >std::function использует больше памяти, чем объект, объявленный с помощью >auto. Кроме того, из-за деталей реализации это ограничивает возможности встраивания и приводит к косвенным вызовам функции, так что вызовы замыкания через объект >std::function обычно выполняются медленнее, чем вызовы посредством объекта, объявленного как >auto. Другими словами, подход с использованием >std::function в общем случае более громоздкий, требующий больше памяти и более медленный, чем подход с помощью >auto, и к тому же может приводить к генерации исключений, связанных с нехваткой памяти. Ну и, как вы уже видели в примерах выше, написать “>auto” — гораздо проще, чем указывать тип для инстанцирования >std::function. В соревновании между >auto и >std::function для хранения замыкания побеждает >auto. (Подобные аргументы можно привести и в пользу предпочтения >auto перед >std::function для хранения результатов вызовов >std::bind, но все равно в разделе 6.4 я делаю все, чтобы убедить вас использовать вместо >std::bind лямбда-выражения...)

Преимущества >auto выходят за рамки избегания неинициализированных переменных, длинных объявлений переменных и возможности непосредственного хранения замыкания. Кроме того, имеется возможность избежать того, что я называю проблемой “сокращений типа” (type shortcuts). Вот кое-что, что вы, вероятно, уже видели, а возможно, даже писали:

>std::vector v;

>…

>unsigned sz = v.size();

Официальный возвращаемый тип >v.size()>std::vector::size_type, но об этом знает не так уж много разработчиков. >std::vector::size_type определен как беззнаковый целочисленный тип, так что огромное количество программистов считают, что >unsigned вполне достаточно, и пишут исходные тексты, подобные показанному выше. Это может иметь некоторые интересные последствия. В 32-разрядной Windows, например, и >unsigned, и >std::vector::size_type имеют один и тот же размер, но в 64-разрядной Windows >unsigned содержит 32 бита, а >std::vector::size_type — 64 бита. Это означает, что код, который работал в 32-разрядной Windows, может вести себя некорректно в 64-разрядной Windows. И кому хочется тратить время на подобные вопросы при переносе приложения с 32-разрядной операционной системы на 64-разрядную?


Еще от автора Скотт Мейерс
Эффективное использование STL

В этой книге известный автор Скотт Мейерс раскрывает секреты настоящих мастеров, позволяющие добиться максимальной эффективности при работе с библиотекой STL.Во многих книгах описываются возможности STL, но только в этой рассказано о том, как работать с этой библиотекой. Каждый из 50 советов книги подкреплен анализом и убедительными примерами, поэтому читатель не только узнает, как решать ту или иную задачу, но и когда следует выбирать то или иное решение — и почему именно такое.


Как функции, не являющиеся методами, улучшают инкапсуляцию

Когда приходится инкапсулировать, то иногда лучше меньше, чем большеЯ начну со следующего утверждения: Если вы пишете функцию, которая может быть выполнена или как метод класса, или быть внешней по отношению к классу, Вы должны предпочесть ее реализацию без использования метода. Такое решение увеличивает инкапсуляцию класса. Когда Вы думаете об использовании инкапсуляции, Вы должны думать том, чтобы не использовать методы.Удивлены? Читайте дальше.


Рекомендуем почитать
Изучаем Java EE 7

Java Enterprise Edition (Java EE) остается одной из ведущих технологий и платформ на основе Java. Данная книга представляет собой логичное пошаговое руководство, в котором подробно описаны многие спецификации и эталонные реализации Java EE 7. Работа с ними продемонстрирована на практических примерах. В этом фундаментальном издании также используется новейшая версия инструмента GlassFish, предназначенного для развертывания и администрирования примеров кода. Книга написана ведущим специалистом по обработке запросов на спецификацию Java EE, членом наблюдательного совета организации Java Community Process (JCP)


Виртуальная библиотека Delphi

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


Обработка баз данных на Visual Basic.NET

Это практическое руководство разработчика программного обеспечения на Visual Basic .NET и ADO.NET, предназначенное для создания приложений баз данных на основе WinForms, Web-форм и Web-служб. В книге описываются практические способы решения задач доступа к данным, с которыми сталкиваются разработчики на Visual Basic .NET в своей повседневной деятельности. Книга начинается с основных сведений о создании баз данных, использовании языка структурированных запросов SQL и системы управления базами данных Microsoft SQL Server 2000.


Исчерпывающее руководство по написанию всплывающих подсказок

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


Программное обеспечение встроенных систем. Общие требования к разработке и документированию

Embedded system software. General requirements for development and documentationСтандарт подготовлен в развитие ГОСТ Р ИСО/МЭК 12207-99 «Информационная технология. Процессы жизненного цикла программных средств» с целью учета специфики разработки и документирования программного обеспечения встроенных систем реального времени.


Как пасти котов. Наставление для программистов, руководящих другими программистами

«Как пасти котов» – это книга о лидерстве и руководстве, о том, как первое совмещать со вторым. Это, если хотите, словарь трудных случаев управления IT-проектами. Программист подобен кошке, которая гуляет сама по себе. Так уж исторически сложилось. Именно поэтому так непросто быть руководителем команды разработчиков. Даже если вы еще месяц назад были блестящим и дисциплинированным программистом и вдруг оказались в роли менеджера, вряд ли вы знаете, с чего надо начать, какой выбрать стиль руководства, как нанимать и увольнять сотрудников, проводить совещания, добиваться своевременного выполнения задач.