Скотт Мейерс - Эффективный и современный С++. 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 - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
• Захват перемещением. Лямбда-выражения С++11 не предоставляют возможности захвата перемещением, но его можно эмулировать с помощью комбинации лямбда- выражения и std::bind
. Детали описываются в разделе 6.2, в котором также поясняется, что в С++14 поддержка инициализирующего захвата в лямбда-выражениях устраняет необходимость в такой эмуляции.
• Полиморфные функциональные объекты. Поскольку оператор вызова функции bind-объекта использует прямую передачу, он может принимать аргументы любого типа (с учетом ограничений на прямую передачу, описанных в разделе 5.8). Это может быть полезным, когда вы хотите связать объект с шаблонным оператором вызова функции. Например, для класса
class PolyWidget {
public:
template
void operator()(const T& param);
…
};
std::bind
может связать PolyWidget
следующим образом:
PolyWidget pw;
auto boundPW = std::bind(pw, _1);
После этого boundPW
может быть вызван с разными типами аргументов:
boundPW(1930); // Передача int в PolyWidget::operator()
boundPW(nullptr); // Передача nullptr в PolyWidget::operator()
boundPW("Rosebud"); // Передача строкового литерала
Выполнить это с помощью лямбда-выражений С++11 невозможно. Однако в С++14 этого легко достичь с помощью лямбда-выражения с параметром auto
:
auto boundPW = [pw](const auto¶m) // С++14
{ pw(param); };
Конечно, это крайние случаи, и они встречаются все реже, поскольку поддержка С++14 лямбда-выражений компиляторами становится все более распространенной.
Когда bind
был неофициально добавлен в С++ в 2005 году, это было существенным усовершенствованием по сравнению с его предшественником 1998 года. Однако добавление поддержки лямбда-выражений в C++11 привело к устареванию std::bind
, а с момента появления С++14 для него, по сути, не осталось применений.
• Лямбда-выражения более удобочитаемы, более выразительны и могут быть более эффективными по сравнению с std::bind
.
• Только в C++11 std::bind
может пригодиться для реализации перемещающего захвата или для связывания объектов с шаблонными операторами вызова функции.
Глава 7
Параллельные вычисления
Одним из наибольших триумфов С++ 11 является включение параллелизма в язык программирования и библиотеку. Программисты, знакомые с другими потоковыми API (например, pthreads или Windows threads), иногда удивляются сравнительно спартанскому набору возможностей, предлагаемому С++, но это связано с тем, что по большей части поддержка параллельности в С++ имеет вид ограничений для разработчиков компиляторов. Получаемые в результате языковые гарантии означают, что впервые в истории С++ программисты могут писать многопоточные приложения со стандартным поведением на всех платформах. Это создает прочный фундамент, на котором могут быть построены выразительные библиотеки, а элементы параллелизма в стандартной библиотеке (задачи, фьючерсы, потоки, мьютексы, переменные условий, атомарные объекты и прочие) являются лишь началом того, что обязательно станет более богатым набором инструментов для разработки параллельного программного обеспечения на С++.
В последующих разделах нужно иметь в виду, что стандартная библиотека содержит два шаблона для фьючерсов: std::future
и std::shared_future
. Во многих случаях различия между ними не важны, так что я часто говорю просто о фьючерсах , подразумевая при этом обе разновидности.
7.1. Предпочитайте программирование на основе задач программированию на основе потоков
Если вы хотите выполнить функцию doAsyncWork
асинхронно, у вас есть два основных варианта. Вы можете создать std::thread
и запустить с его помощью doAsyncWork
, тем самым прибегнув к подходу на основе потоков :
int doAsyncWork();
std::threadt(doAsyncWork);
Вы также можете передать doAsyncWork
в std::async
, воспользовавшись стратегией, известной как подход на основе задач :
auto fut = std::async(doAsyncWork); // "fut" от "future"
В таких вызовах функциональный объект, переданный в std::async
(например, doAsyncWork
), рассматривается как задача (task).
Подход на основе задач обычно превосходит свой аналог на основе потоков, и небольшие фрагменты кода, с которыми вы встретились выше, показывают некоторые причины этого. Здесь doAsyncWork
дает возвращаемое значение, в котором, как мы можем разумно предположить, заинтересован вызывающий doAsyncWork
код. В случае вызова на основе потоков нет простого способа к нему обратиться. При подходе на основе потоков нет простого способа получить доступ к вызову. В случае же подхода на основе задач это можно легко сделать, поскольку фьючерс, возвращаемый std::async
, предлагает функцию get
. Эта функция get
еще более важна, если doAsyncWork
генерирует исключение, поскольку get
обеспечивает доступ и к нему. При подходе на основе потоков в случае генерации функцией doAsyncWork
исключения программа аварийно завершается (с помощью вызова std::terminate
).
Более фундаментальным различием между подходами на основе потоков и на основе задач является воплощение более высокого уровня абстракции в последнем. Он освобождает вас от деталей управления потоками, что, кстати, напомнило мне о необходимости рассказать о трех значениях слова поток (thread) в параллельном программировании на С++.
• Аппаратные потоки являются потоками, которые выполняют фактические вычисления. Современные машинные архитектуры предлагают по одному или по нескольку аппаратных потоков для каждого ядра процессора.
• Программные потоки (известные также как потоки ОС или системные потоки ) являются потоками, управляемыми операционной системой [21] В предположении, что таковая имеется. В некоторых встроенных системах ее нет.
во всех процессах и планируемыми для выполнения аппаратными потоками. Обычно можно создать программных потоков больше, чем аппаратных, поскольку, когда программный поток заблокирован (например, при вводе-выводе или ожидании мьютекса или переменной условия), пропускная способность может быть повышена путем выполнения других, незаблокированных потоков.
• std::thread
представляют собой объекты в процессе С++, которые действуют как дескрипторы для лежащих в их основе программных потоков. Некоторые объекты std::thread
представляют “нулевые” дескрипторы, т.e. не соответствуют программным потокам, поскольку находятся в состоянии, сконструированном по умолчанию (следовательно, без выполняемой функции); потоки, из которых выполнено перемещение (после перемещения объект std::thread
, в который оно произошло, действует как дескриптор для соответствующего программного потока); потоки, у которых выполняемая ими функция завершена; а также потоки, у которых разорвана связь между ними и обслуживающими их программными потоками.
Интервал:
Закладка: