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

Тут можно читать онлайн Скотт Мейерс - Эффективный и современный С++. 42 рекомендации по использованию С++11 и С++14 - бесплатно полную версию книги (целиком) без сокращений. Жанр: comp-programming, издательство Вильямс, год 2016. Здесь Вы можете читать полную версию (весь текст) онлайн без регистрации и SMS на сайте лучшей интернет библиотеки ЛибКинг или прочесть краткое содержание (суть), предисловие и аннотацию. Так же сможете купить и скачать торрент в электронном формате fb2, найти и слушать аудиокнигу на русском языке или узнать сколько частей в серии и всего страниц в публикации. Читателям доступно смотреть обложку, картинки, описание и отзывы (комментарии) о произведении.
  • Название:
    Эффективный и современный С++. 42 рекомендации по использованию С++11 и С++14
  • Автор:
  • Жанр:
  • Издательство:
    Вильямс
  • Год:
    2016
  • Город:
    Москва
  • ISBN:
    978-5-8459-2000-3
  • Рейтинг:
    3/5. Голосов: 11
  • Избранное:
    Добавить в избранное
  • Отзывы:
  • Ваша оценка:
    • 60
    • 1
    • 2
    • 3
    • 4
    • 5

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

Эффективный и современный С++. 42 рекомендации по использованию С++11 и С++14 - описание и краткое содержание, автор Скотт Мейерс, читайте бесплатно онлайн на сайте электронной библиотеки LibKing.Ru
Эффективный и современный С++
В книге рассматриваются следующие темы. Освоение С++11 и С++14 — это больше, чем просто ознакомление с вводимыми этими стандартами возможностями (например, объявлениями типов
, семантикой перемещения, лямбда-выражениями или поддержкой многопоточности). Вопрос в том, как использовать их эффективно, чтобы создаваемые программы были корректны, эффективны и переносимы, а также чтобы их легко можно было сопровождать. Именно этим вопросам и посвящена данная книга, описывающая создание по-настоящему хорошего программного обеспечения с использованием C++11 и С++14 — т.е. с использованием современного С++.
■ Преимущества и недостатки инициализации с помощью фигурных скобок, спецификации
, прямой передачи и функций
интеллектуальных указателей
■ Связь между
,
, rvalue-ссылками и универсальными ссылками
■ Методы написания понятных, корректных,
лямбда-выражений
■ Чем
отличается от
, как они используются и как соотносятся с API параллельных вычислений С++
■ Какие из лучших методов “старого” программирования на С++ (т.е. С++98) должны быть пересмотрены при работе с современным С++
Более чем 20 лет книги
серии
являются критерием уровня книг по программированию на С++. Понятное пояснение сложного технического материала принесло ему всемирную известность. Он всегда самый желанный гость на международных конференциях, а его услуги консультанта широко востребованы во всем мире.
Скотт Мейерс Эффективный и современный С++, После изучения основ С++ я перешел к изучению того, как применять С++ в промышленном программировании, с помощью серии книг Скотта Мейерса Эффективный С++. Эффективный и современный С++ — наиболее важная из книг серии, предлагающая ключевые рекомендации, стили и идиомы, позволяющие эффективно использовать современный С++. Вы еще не купили эту книгу? Сделайте это прямо сейчас. Герб Саттер,
глава Комитета ISO по стандартизации С++, специалист в области архитектуры программного обеспечения на С++ в Microsoft

Эффективный и современный С++. 42 рекомендации по использованию С++11 и С++14 - читать онлайн бесплатно полную версию (весь текст целиком)

Эффективный и современный С++. 42 рекомендации по использованию С++11 и С++14 - читать книгу онлайн бесплатно, автор Скотт Мейерс
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать

Объекты std::thread , из которых выполнено перемещение. В результате перемещения поток выполнения, соответствующий std::thread, становится соответствующим другому объекту std::thread.

Объекты std::thread , для которых выполнена функция-член join . После выполнения функции-члена join объект std::thread больше не соответствует потоку выполнения, который при этом вызове полностью завершается.

Объекты std::thread , для которого выполнена функция-член detach . Функция-член detachразрывает связь между объектом std::threadи соответствующим ему потоком выполнения.

Одной из причин, по которым так важна подключаемость std::thread, является то, что при вызове деструктора для подключаемого объекта программа завершает свою работу. Предположим, например, что у нас есть функция doWork, которая получает функцию фильтрации filterи максимальное значение maxValв качестве параметров. Функция doWorkвыполняет проверку, чтобы убедиться, что все условия, необходимые для ее работы, выполнены, а затем выполняет вычисления со всеми значениями от 0 до maxVal, проходящими через фильтр. Если фильтрация и определение выполнения условий для функции doWorkтребуют большого времени выполнения, может быть разумным выполнить эти два действия параллельно.

Мы бы предпочли воспользоваться советом из раздела 7.1 и программировать параллельность на основе задач, но предположим, что нам надо установить приоритет потока, выполняющего фильтрацию. Как пояснялось в разделе 7.1, для этого требуется системный дескриптор потока, а он доступен только через API std::thread; API задач (т.e. фьючерсы) такой возможности не предоставляет. Поэтому мы работаем с потоками, а не с задачами.

Мы могли бы начать с кода наподобие следующего:

// См. constexpr в разделе 3.9

constexpr auto tenMillion = 10000000;

// Возвращает значение, указывающее, были ли выполнены

// вычисления; std::function см. в разделе 2.1

bool doWork(std::function filter,

int maxVal = tenMillion) {

// Значения, удовлетворяющие фильтру:

std::vector goodVals;

// Заполнение goodVals:

std::thread t([&filter, maxVal, &goodVals] {

for (auto i = 0; i <= maxVal; ++i) {

if (filter(i)) goodVals.push_back(i); }

});

// Используем системный дескриптор потока для

// установки приоритета:

auto nh = t.native_handle();

if ( conditionsAreSatisfied() ) {

t.join(); // Завершаем t

performComputation(goodVals);

return true; // Вычисление выполнено

}

return false; // Вычисление не выполнено

}

Перед тем как пояснить, почему этот код проблематичен, я замечу, что инициализирующее значение tenMillionв С++14 можно сделать более удобочитаемым, воспользовавшись возможностью C++14 использовать апостроф для разделения цифр:

constexpr auto tenMillion = 10'000'000; // С++14

Замечу также, что установка приоритета tпосле его запуска напоминает забивание двери конюшни после того, как лошадь уже убежала. Лучше начинать с tв приостановленном состоянии (тем самым делая возможным изменение его приоритета до выполнения вычислений), но я не хочу отвлекать вас этим кодом. Потерпите до раздела 7.5, в нем показано, как начинать работать с потоками в приостановленном состоянии.

Вернемся к функции doWork. Если вызов conditionsAreSatisfied()возвращает true, все в порядке, но если он вернет значение falseили сгенерирует исключение, объект tбудет подключаемым в момент вызова деструктора при окончании работы doWork. Это приведет к завершению работы программы.

Вы можете удивиться, почему деструктор std::threadведет себя столь неподобающе. Да просто потому, что два других варианта, описанных далее, еще хуже.

Неявный вызов join . В этом случае деструктор std::threadбудет ожидать завершения соответствующего асинхронного потока. Звучит разумно, но может привести к аномалиям производительности, которые будет трудно отследить. Например, было бы нелогичным, чтобы функция doWorkожидала применения фильтра ко всем значениям, если вызов conditionsAreSatisfied()уже вернул значение false.

Неявный вызов detach . В этом случае деструктор std::threadразрывает связь между объектом std::threadи его потоком, отключая последний от объекта. Поток продолжает выполняться. Это звучит не менее разумно, чем применение join, но проблемы отладки, к которым это может привести, делают этот вариант еще худшим. Например, в функции doWorkлокальная переменная goodValsзахватывается лямбда-выражением по ссылке. Она также изменяется в лямбда-выражении (с помощью вызова push_back). Предположим теперь, что во время асинхронного выполнения лямбда-выражения вызов conditionsAreSatisfied()вернул false. В таком случае функция doWorkдолжна завершиться, а ее локальные переменные (включая goodVals) должны быть уничтожены. Ее кадр стека удаляется, и выполнение потока продолжается с точки вызова doWork.

Инструкции после этой точки могут в некоторой иной точке выполнять вызовы других функций, и как минимум одна из них может занять место в стеке, ранее занятое кадром стека doWork. Назовем эту функцию f. Во время работы fлямбда-выражение из doWorkпродолжает асинхронно выполняться и может вызвать push_backдля памяти в стеке, которая ранее использовалась для локальной переменной goodVals, а теперь принадлежит кадру стека f. Такой вызов может изменить память, использовавшуюся для goodVals, а это означает, что с точки зрения fсодержимое памяти в ее кадре стека может внезапно измениться! Только представьте себе, что вам придется отлаживать такое .

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

Это решение возлагает на вас ответственность за то, что если вы используете объект std::thread, то должны сделать его неподключаемым на всех путях из области видимости, в которой он определен. Но охват всех путей может быть весьма сложным. Он включает как нормальный выход из области видимости, так и такие выходы, как с помощью return, continue, break, gotoили исключения. Этих путей может быть великое множество.

Всякий раз, когда надо выполнить некоторое действие на всех путях, ведущих из блока, естественным подходом является размещение этого действия в деструкторе локального объекта. Такие объекты известны как объекты RAII , а соответствующие классы — классы RAII . ( RAII означает “Resource Acquisition Is Initialization”, “захват ресурса есть инициализация”, хотя на самом деле речь идет о методе деструкции, а не инициализации.) RAII-классы — распространенное явление в стандартной библиотеке. Примерами являются контейнеры STL (деструктор каждого контейнера уничтожает его содержимое и освобождает память), стандартные интеллектуальные указатели (в разделах 4.1-4.3 поясняется, что деструктор std::unique_ptrвызывает удалитель для объекта, на который указывает, а деструкторы std::shared_ptrи std::weak_ptrуменьшают счетчики ссылок), объекты std::fstream(их деструкторы закрывают соответствующие файлы) и многое другое. Тем не менее стандартного RAII-класса для объектов std::threadнет, вероятно, потому что Комитет по стандартизации, отвергнув и join, и detachкак варианты по умолчанию, просто не знал, что же должен делать такой класс.

Читать дальше
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать


Скотт Мейерс читать все книги автора по порядку

Скотт Мейерс - все книги автора в одном месте читать по порядку полные версии на сайте онлайн библиотеки LibKing.




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


Отзывы читателей о книге Эффективный и современный С++. 42 рекомендации по использованию С++11 и С++14, автор: Скотт Мейерс. Читайте комментарии и мнения людей о произведении.


Понравилась книга? Поделитесь впечатлениями - оставьте Ваш отзыв или расскажите друзьям

Напишите свой комментарий
x