Скотт Мейерс - Эффективный и современный С++. 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 - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
processedWidgets.emplace_back( shared_from_this());
}
Внутри себя shared_from_this
ищет управляющий блок текущего объекта и создает новый std::shared_ptr
, который использует этот управляющий блок. Дизайн функции полагается на тот факт, что текущий объект имеет связанный с ним управляющий блок. Чтобы это было так, должен иметься уже существующий указатель std::shared_ptr
(например, за пределами функции-члена, вызывающей shared_from_this
), который указывает на текущий объект. Если такого std::shared_ptr
нет (т.e. если текущий объект не имеет связанного с ним управляющего блока), результатом будет неопределенное поведение, хотя обычно shared_from_this
генерирует исключение.
Чтобы препятствовать клиентам вызывать функции-члены, в которых используется shared_from_this
, до того как на объект будет указывать указатель std::shared_ptr
, классы, наследуемые от std::enable_shared_from_this
, часто объявляют свои конструкторы как private и заставляют клиентов создавать объекты путем вызова фабричных функций, которые возвращают указатели std::shared_ptr
. Например, класс Widget
может выглядеть следующим образом:
class Widget: public std::enable_shared_from_this {
public:
// Фабричная функция, пересылающая
// аргументы закрытому конструктору:
template
static std::shared_ptr create(Ts&&... params);
…
void process(); // Как и ранее
…
private:
… // Конструкторы
};
В настоящее время вы можете только смутно припоминать, что наше обсуждение управляющих блоков было мотивировано желанием понять, с какими затратами связано применение std::shared_ptr
. Теперь, когда мы понимаем, как избегать создания слишком большого количества управляющих блоков, вернемся к нашей первоначальной теме.
Управляющий блок обычно имеет размер в несколько слов, хотя пользовательские удалители и распределители памяти могут его увеличить. Обычная реализация управляющего блока оказывается более интеллектуальной, чем можно было бы ожидать. Она применяет наследование, и при этом даже имеются виртуальные функции. (Все это требуется для того, чтобы обеспечить корректное уничтожение указываемого объекта.) Это означает, что применение указателей std::shared_ptr
берет на себя также стоимость механизма виртуальной функции, используемой управляющим блоком.
Возможно, после того как вы прочли о динамически выделяемых управляющих блоках, удалителях и распределителях неограниченного размера, механизме виртуальных функций и атомарности работы со счетчиками ссылок, ваш энтузиазм относительно std::shared_ptr
несколько угас. Это нормально.
Они не являются наилучшим решением для любой задачи управления ресурсами. Но для предоставляемой ими функциональности цена std::shared_ptr
весьма разумна. В типичных условиях, когда использованы удалитель и распределитель памяти по умолчанию, а std::shared_ptr
создается с помощью std::make_shared
, размер управляющего блока составляет около трех слов, и его выделение, по сути, ничего не стоит. (Оно встроено в выделение памяти для указываемого им объекта. Дополнительная информация об этом приведена в разделе 4.4.) Разыменование std::shared_ptr
не более дорогостояще, чем разыменование обычного указателя. Выполнение операций, требующих работы со счетчиком ссылок (например, копирующий конструктор или копирующее присваивание, удаление) влечет за собой одну или две атомарные операции, но эти операции обычно отображаются на отдельные машинные команды, так что, хотя они могут быть дороже неатомарных команд, они все равно остаются отдельными машинными командами. Механизм виртуальных функций в управляющем блоке обычно используется только однажды для каждого объекта, управляемого указателями std::shared_ptr
: когда происходит уничтожение объекта.
В обмен на эти весьма скромные расходы вы получаете автоматическое управление временем жизни динамически выделяемых ресурсов. В большинстве случаев применение std::shared_ptr
значительно предпочтительнее, чем ручное управление временем жизни объекта с совместным владением. Если вы сомневаетесь, можете ли вы позволить себе использовать std::shared_ptr
, подумайте, точно ли вам нужно обеспечить совместное владение. Если вам достаточно или даже может быть достаточно исключительного владения, лучшим выбором является std::unique_ptr
. Его профиль производительности близок к таковому для обычных указателей, а “обновление” std::unique_ptr
до std::shared_ptr
выполняется очень легко, так как указатель std::shared_ptr
может быть создан из указателя std::unique_ptr
.
Обратное неверно. После того как вы включили управление временем жизни ресурса с помощью std::shared_ptr
, обратной дороги нет. Даже если счетчик ссылок равен единице, нельзя вернуть владение ресурсом для того, чтобы, скажем, им управлял std::unique_ptr
. Контракт владения между ресурсом и указателями std::shared_ptr
, которые указывают на ресурс, написан однозначно — “пока смерть не разлучит нас”. Никаких разводов и раздела имущества не предусмотрено.
Есть еще кое-что, с чем не могут справиться указатели std::shared_ptr
, — массивы. Это еще одно их отличие от указателей std::unique_ptr
. Класс std::shared_ptr
имеет API, предназначенное только для работы с указателями на единственные объекты. Не существует std::shared_ptr
. Время от времени “крутые” программисты натыкаются на мысль использовать std::shared_ptr
для указания на массив, определяя пользовательский удалитель для выполнения освобождения массива (т.e. delete[]
). Это можно сделать и скомпилировать, но это ужасная идея. С одной стороны, класс std::shared_ptr
не предоставляет оператор operator[]
, так что индексирование указываемого массива требует неудобных выражений с применением арифметики указателей. С другой стороны, std:: shared_ptr
поддерживает преобразование указателей на производные классы в указатели на базовые классы, которое имеет смысл только для одиночных объектов, но при применении к массивам оказывается открытой дырой в системе типов. (По этой причине API std::unique_ptr
запрещает такие преобразования.) Что еще более важно, учитывая разнообразие альтернатив встроенным массивам в С++11 (например, std::array
, std::vector
, std::string
), объявление интеллектуального указателя на тупой массив всегда является признаком плохого проектирования.
• std::shared_ptr
предоставляет удобный подход к управлению временем жизни произвольных ресурсов, аналогичный сборке мусора.
• По сравнению с std::unique_ptr
объекты std::shared_ptr
обычно в два раза больше, привносят накладные расходы на работу с управляющими блоками и требуют атомарной работы со счетчиками ссылок.
Интервал:
Закладка: