Скотт Мейерс - Эффективный и современный С++. 42 рекомендации по использованию С++11 и С++14
- Название:Эффективный и современный С++. 42 рекомендации по использованию С++11 и С++14
- Автор:
- Жанр:
- Издательство:Вильямс
- Год:2016
- Город:Москва
- ISBN:978-5-8459-2000-3
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Скотт Мейерс - Эффективный и современный С++. 42 рекомендации по использованию С++11 и С++14 краткое содержание
В книге рассматриваются следующие темы. Освоение С++11 и С++14 — это больше, чем просто ознакомление с вводимыми этими стандартами возможностями (например, объявлениями типов
, семантикой перемещения, лямбда-выражениями или поддержкой многопоточности). Вопрос в том, как использовать их эффективно, чтобы создаваемые программы были корректны, эффективны и переносимы, а также чтобы их легко можно было сопровождать. Именно этим вопросам и посвящена данная книга, описывающая создание по-настоящему хорошего программного обеспечения с использованием C++11 и С++14 — т.е. с использованием современного С++.
■ Преимущества и недостатки инициализации с помощью фигурных скобок, спецификации
, прямой передачи и функций
интеллектуальных указателей
■ Связь между
,
, rvalue-ссылками и универсальными ссылками
■ Методы написания понятных, корректных,
лямбда-выражений
■ Чем
отличается от
, как они используются и как соотносятся с API параллельных вычислений С++
■ Какие из лучших методов “старого” программирования на С++ (т.е. С++98) должны быть пересмотрены при работе с современным С++
Более чем 20 лет книги
серии
являются критерием уровня книг по программированию на С++. Понятное пояснение сложного технического материала принесло ему всемирную известность. Он всегда самый желанный гость на международных конференциях, а его услуги консультанта широко востребованы во всем мире.
Скотт Мейерс Эффективный и современный С++, После изучения основ С++ я перешел к изучению того, как применять С++ в промышленном программировании, с помощью серии книг Скотта Мейерса Эффективный С++. Эффективный и современный С++ — наиболее важная из книг серии, предлагающая ключевые рекомендации, стили и идиомы, позволяющие эффективно использовать современный С++. Вы еще не купили эту книгу? Сделайте это прямо сейчас. Герб Саттер,
глава Комитета ISO по стандартизации С++, специалист в области архитектуры программного обеспечения на С++ в Microsoft
Эффективный и современный С++. 42 рекомендации по использованию С++11 и С++14 - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
В результате w1 представляет собой lvalue-ссылку. С другой стороны, объявление
auto&&w2 = widgetFactory();
инициализирует w2
с помощью rvalue, приводя к тому, что для auto
выводится тип Widget
, не являющийся ссылкой. Подстановка Widget
вместо auto
дает
Widget&&w2 = widgetFactory();
Здесь нет ссылок на ссылки, так что процесс завершен; w2
представляет собой rvalue-ссылку.
Теперь мы в состоянии по-настоящему понять универсальные ссылки, введенные в разделе 5.2. Универсальная ссылка не является новой разновидностью ссылок, в действительности это rvalue-ссылка в контексте, в котором выполняются два условия.
• Вывод типа отличает lvalue от rvalue. lvalue типа T
выводится как имеющее тип T&
, в то время как rvalue типа T
дает в качестве выведенного типа T
.
• Происходит свертывание ссылок.
Концепция универсальных ссылок полезна тем, что избавляет вас от необходимости распознавать наличие контекстов сворачивания, мысленного вывода различных типов для lvalue и rvalue и применения правила свертывания ссылок после мысленной подстановки выведенных типов в контексты, в которых они встречаются.
Я говорил, что имеется четыре контекста, но мы рассмотрели только два из них: инстанцирование шаблонов и генерацию типов auto
. Третьим является генерация и использование typedef
и объявлений псевдонимов (см. раздел 3.3). Если во время создания или вычисления typedef
возникают ссылки на ссылки, для их устранения применяется сворачивание ссылок. Предположим, например, что у нас есть шаблон класса Widget
с внедренным typedef
для типа rvalue-ссылки
template
class Widget {
public:
typedef T&& RvalueRefToT;
};
и предположим, что мы инстанцируем Widget
с помощью типа lvalue-ссылки:
Widget< int&> w;
Подстановка int&
вместо T
в шаблоне Widget
дает нам следующую конструкцию typedef
:
typedef int& &&RvalueRefToT;
Сворачивание ссылок приводит этот код к
typedef int&RvalueRefToT;
Теперь ясно, что имя, которое мы выбрали для typedef
, вероятно, не настолько описательно, как мы надеялись: RvalueRefToT
представляет собой typedef
для lvalue-ссылки , когда Widget
инстанцируется типом lvalue-ссылки.
Последним контекстом, в котором имеет место сворачивание ссылок, является использование decltype
. Если во время анализа типа, включающего decltype
, возникает ссылка на ссылку, она устраняется сворачиванием ссылок. (Информацию о decltype
вы найдете в разделе 1.3.)
• Сворачивание ссылок встречается в четырех контекстах: инстанцирование шаблона, генерация типа auto
, создание и применение typedef
и объявлений псевдонимов, и decltype
.
• Когда компиляторы генерируют ссылку на ссылку в контексте сворачивания ссылок, результатом становится единственная ссылка. Если любая из исходных ссылок является lvalue-ссылкой, результатом будет lvalue-ссылка; в противном случае это будет rvalue-ссылка.
• Универсальные ссылки представляют собой rvalue-ссылки в контекстах, в которых вывод типов отличает lvalue от rvalue и происходит сворачивание ссылок.
5.7. Считайте, что перемещающие операции отсутствуют, дороги или не используются
Семантика перемещения, пожалуй, самая главная возможность С++11. Вам наверняка приходилось слышать, что “перемещение контейнеров теперь такое же дешевое, как и копирование указателей” или что “копирование временных объектов теперь настолько эффективно, что избегать его равносильно преждевременной оптимизации”. Понять такие настроения легко. Семантика перемещения действительно является очень важной возможностью. Она не просто позволяет компиляторам заменять дорогостоящие операции копирования относительно дешевыми перемещениями, но и требует от них этого (при выполнении надлежащих условий). Возьмите ваш код С++98, перекомпилируйте его с помощью компилятора и стандартной библиотеки С++11 и — о чудо! — ваша программа заработает быстрее.
Семантика перемещения действительно в состоянии осуществить все это — и потому достойна легенды. Однако легенды, как правило, — это результат преувеличения. Цель данного раздела — спустить вас с небес на землю.
Начнем с наблюдения, что многие типы не поддерживают семантику перемещения. Вся стандартная библиотека С++98 была переработана с целью добавления операций перемещения для типов, в которых перемещение могло быть реализовано быстрее копирования, и реализации компонентов библиотеки были пересмотрены с целью использования преимуществ новых операций; однако есть вероятность, что вы работаете с кодом, который не был полностью переделан под C++11. Для типов в ваших приложениях (или в используемых вами библиотеках), в которые не были внесены изменения для С++11, мало пользы от наличия поддержки перемещения компилятором. Да, С++ 11 готов генерировать перемещающие операции для классов, в которых они отсутствуют, но это происходит только для классов, в которых не объявлены копирующие операции, перемещающие операции или деструкторы (см. раздел 3.11). Члены-данные базовых классов типов, в которых перемещения отключены (например, путем удаления перемещающих операций; см. раздел 3.5) также подавляют перемещающие операции, генерируемые компиляторами. Для типов без явной поддержки перемещения и типов, которые не могут претендовать на перемещающие операции, генерируемые компилятором, нет оснований ожидать что С++11 обеспечит повышение производительности по сравнению с С++98.
Даже типы с явной поддержкой перемещений не могут обеспечить все, на что вы надеетесь. Например, все контейнеры стандартной библиотеки С++11 поддерживают перемещение, но было бы ошибкой считать, что перемещение является дешевой операцией для всех контейнеров. Для одних контейнеров это связано с тем, что нет никакого действительно дешевого способа перемещения их содержимого. Для других — с тем, что действительно дешевые перемещающие операции предлагаются контейнерами с оговорками, которым не удовлетворяют конкретные элементы контейнера.
Рассмотрим новый контейнер C++11 — std::array
. Контейнер std::array
, по сути, представляет собой встроенный массив с STL-интерфейсом. Он фундаментально отличается от других стандартных контейнеров, которые хранят свое содержимое в динамической памяти. Объекты таких типов контейнеров концептуально содержат (в качестве членов-данных) только указатель на динамическую память, хранящую содержимое контейнера. (Действительность более сложна, но для наших целей эти отличия не играют роли.) Наличие такого указателя позволяет перемещать содержимое всего контейнера на константное время: просто копируя указатель на содержимое контейнера из исходного контейнера в целевой и делая указатель исходного контейнера нулевым:
Интервал:
Закладка: