Скотт Мейерс - Эффективный и современный С++. 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 - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Реализация fastLoadWidget
игнорирует тот факт, что кеш может накапливать просроченные указатели std::weak_ptr
, соответствующие объектам Widget
, которые больше не используются (а значит, были уничтожены). Реализация может быть улучшена, но вместо того чтобы тратить время на вопрос, который не привнесет ничего нового в понимание интеллектуальных указателей std::weak_ptr
, давайте рассмотрим второе применение этих указателей: шаблон проектирования Observer (Наблюдатель). Основными компонентами этого шаблона являются субъекты (объекты, которые могут изменяться) и наблюдатели (объекты, уведомляемые при изменении состояний). В большинстве реализаций каждый субъект содержит член-данные, хранящие указатели на его наблюдателей. Это упрощает для субъектов проблемы уведомления об изменении состояний. Субъекты не заинтересованы в управлении временем жизни своих наблюдателей (т.e. тем, когда они должны быть уничтожены), но они очень заинтересованы в том, чтобы, если наблюдатель был уничтожен, субъекты не пытались к нему обратиться. Разумным проектом может быть следующий — каждый субъект хранит контейнер указателей std::weak_ptr
на своих наблюдателей, тем самым позволяя субъекту определять, не является ли указатель висящим, перед тем как его использовать.
В качестве последнего примера применения std::weak_ptr
рассмотрим структуру данных с объектами А
, В
и С
в ней, где А
и С
совместно владеют В
, а следовательно, хранят указатели std::shared_ptr
на нее:

Предположим, что было бы также полезно иметь указатель из в на А
. Какую разновидность интеллектуального указателя следует использовать в этом случае?

Есть три варианта.
• Обычный указатель. При таком подходе, если уничтожается А
, а С
продолжает указывать на В
, В
будет содержать указатель на А
, который становится висящим. В
не в состоянии этого определить, а потому В
может непреднамеренно этот указатель разыменовать. В результате получается неопределенное поведение.
• Указатель std::shared_ptr
. В этом случае А
и В
содержат указатели std::shared_ptr
один на другой. Получающийся цикл std::shared_ptr
( А
указывает на В
, а В
указывает на А
) предохраняет и А
, и В
от уничтожения. Даже если А
и В
недостижимы из других структур данных программы (например, поскольку С
больше не указывает на В
), счетчик ссылок каждого из них равен единице. Если такое происходит, А
и В
оказываются потерянными всех практических применений: программа не в состоянии к ним обратиться, а их ресурсы не могут быть освобождены.
• Указатель std::weak_ptr
. Это позволяет избежать обеих описанных выше проблем. Если уничтожается А
, указатель в B
становится висящим, но В
в состоянии это обнаружить. Кроме того, хотя А
и В
указывают друг на друга, указатель в В
не влияет на счетчик ссылок А
, а следовательно, не может предотвратить удаление А
, когда на него больше не указывает ни один std::shared_ptr
.
Очевидно, что наилучшим выбором является std::weak_ptr
. Однако стоит отметить, что необходимость применения указателей std::weak_ptr
для предотвращения потенциальных циклов из указателей std::shared_ptr
не является очень распространенным явлением. В строго иерархических структурах данных, таких как деревья, дочерними узлами обычно владеют их родительские узлы. При уничтожении родительского узла должны уничтожаться и его дочерние узлы. В общем случае связи от родительских к дочерним узлам лучше представлять указателями std::unique_ptr
. Обратные связи от дочерних узлов к родительским можно безопасно реализовывать, как обычные указатели, поскольку дочерний узел никогда не должен иметь время жизни, большее, чем время жизни его родительского узла. Таким образом, отсутствует риск того, что дочерний узел разыменует висячий родительский указатель.
Конечно, не все структуры данных на основе указателей строго иерархичны, и когда приходится сталкиваться с такими неиерархичными ситуациями, как и с ситуациями наподобие кеширования или реализации списков наблюдателей, знайте, что у вас есть такой инструмент, как std::weak_ptr
.
С точки зрения эффективности std::weak_ptr
, по сути, такой же, как и std::shared_ptr
. Объекты std::weak_ptr
имеют тот же размер, что и объекты std::shared_ptr
, они используют те же управляющие блоки, что и указатели std::shared_ptr
(см. раздел 4.2), а операции, такие как создание, уничтожение и присваивание, включают атомарную работу со счетчиком ссылок. Вероятно, это вас удивит, поскольку в начале этого раздела я писал, что указатели std::weak_ptr
не участвуют в подсчете ссылок. Но это не совсем то, что я написал. Я написал, что указатели std::weak_ptr
не участвуют в совместном владении объектами, а следовательно, не влияют на счетчик ссылок указываемого объекта . На самом деле в управляющем блоке имеется второй счетчик ссылок, и именно с ним и работают указатели std::weak_ptr
. Более подробно этот вопрос рассматривается в разделе 4.4.
• Используйте s td::weak_ptr
как std::shared_ptr
-oбpaзныe указатели, которые могут быть висячими.
• Потенциальные применения std::weak_ptr
включают хеширование, списки наблюдателей и предупреждение циклов указателей std::shared_ptr
.
4.4. Предпочитайте использование std::make_unique
и std::make_shared
непосредственному использованию оператора new
Начнем с выравнивания игровой площадки для игры std::make_unique
и std::make_shared
против обычных указателей. Функция std::make_shared
является частью C++11, но, увы, std::make_unique
таковой не является. Она вошла в стандарт только начиная с С++14. Если вы используете С++11, не переживайте, потому что базовую версию std::make_unique
легко написать самостоятельно. Смотрите сами:
template
std::unique_ptr make_unique(Ts&&... params) {
return std::unique_ptr(
new T(std::forward(params)...));
}
Как вы можете видеть, make_unique
просто выполняет прямую передачу своих параметров в конструктор создаваемого объекта, создает std::unique_ptr
из обычного указателя, возвращаемого оператором new
, и возвращает этот указатель std::unique_ptr
. Функция в данном виде не поддерживает массивы или пользовательские удалители (см. раздел 4.1), но зато демонстрирует, как с минимальными усилиями можно при необходимости создать make_unique
[13] Дня создания полнофункциональной версии make_unique с минимальными усилиями поищите документ, ставший ее источником, и скопируйте из него ее реализацию. Этот документ — N3656 от 18 апреля 2013 года, его автор — Стивен T. Лававей (Stephan T. Lavavej).
. Только не помещайте вашу версию в пространство имен std
, поскольку иначе вы можете столкнуться с коллизией имен при обновлении реализации стандартной библиотеки до С++14.
Интервал:
Закладка: