Скотт Мейерс - Эффективный и современный С++. 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 - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Ну, конечно же, вы отлично все это знаете. Да, да, древняя история: Месопотамия, династия Цинь, Владимир Красное Солнышко, FORTRAN, С++98… Но времена изменились, а с ними изменились и правила генерации специальных функций-членов в С++. Важно быть в курсе новых правил, потому что мало вещей имеют такое же важное значение для эффективного программирования на С++, как знание о том, когда компиляторы молча добавляют функции-члены в ваши классы.
Что касается С++11, то в клуб специальных функций-членов приняты два новых игрока: перемещающий конструктор и оператор перемещающего присваивания. Их сигнатуры имеют следующий вид:
class Widget {
public:
…
Widget(Widget&& rhs); // Перемещающий конструктор
Widget& operator=(Widget&& rhs);// Оператор перемещающего
// присваивания
};
Правила, регулирующие их создание и поведение, аналогичны правилам для их копирующих двойников. Перемещающие операции генерируются только если они необходимы, и если они генерируются, то выполняют “почленное перемещение” нестатических членов-данных класса. Это означает, что перемещающий конструктор создает каждый нестатический член-данные класса из соответствующего члена его параметра rhs
с помощью перемещения, а оператор перемещающего присваивания выполняет перемещающее присваивание каждого нестатического члена-данных из переданного ему параметра. Перемещающий конструктор также выполняет перемещающее конструирование частей базового класса (если таковые имеются), а оператор перемещающего присваивания выполняет соответственно перемещающее присваивание частей базового класса.
Когда я говорю о перемещающей операции над членом-данными или базовым классом, нет никакой гарантии, что перемещение в действительности имеет место. “Почленные перемещения” в действительности представляют собой запросы на почленное перемещение, поскольку типы, которые не могут быть перемещены (т.e. не обладают поддержкой операций перемещения; например, таковыми являются большинство старых классов С++98), будут “перемещены” с помощью операций копирования. Сердцем каждого почленного “перемещения” является применение std::move
к объекту, из которого выполняется перемещение, а результат используется в процессе разрешения перегрузки функций для выяснения, должно ли выполняться перемещение или копирование. Этот процесс детально описывается в разделе 5.1. В этом разделе просто помните, что почленное перемещение состоит из операций перемещения для тех членов-данных и базовых классов, которые поддерживают перемещающие операции, и из операций копирования для тех, которые перемещающие операции не поддерживают.
Как и в случае с копирующими операциями, перемещающие операции не генерируются, если вы сами их не объявляете. Однако точные условия, при которых они генерируются, несколько отличаются от условий для копирующих операций.
Две копирующие операции независимы одна от другой: объявление одной не препятствует компилятору генерировать другую. Так что если вы объявляете копирующий конструктор, но не копирующий оператор присваивания, а затем пишете код, которому требуется копирующее присваивание, то компиляторы будут генерировать оператор копирующего присваивания вместо вас. Аналогично, если вы объявили оператор копирующего присваивания, но не копирующий конструктор, а вашему коду нужен копирующий конструктор, то последний будет сгенерирован компилятором вместо вас. Это правило работало в С++98 и остается справедливым в C++11.
Две перемещающие операции не являются независимыми. Если вы объявите одну из них, это не позволит компиляторам сгенерировать вторую. Это объясняется тем, что если вы объявляете, скажем, перемещающий конструктор для вашего класса, то вы указываете, что есть что-то, что при перемещающем конструировании должно быть реализовано иначе, чем почленное перемещение по умолчанию, генерируемое компиляторами. Но если это что-то неверно при почленном перемещающем конструировании, то, вероятно, оно будет неверно и при почленном перемещающем присваивании. Поэтому объявление перемещающего конструктора предохраняет от генерации перемещающего оператора присваивания, а объявление перемещающего оператора присваивания предохраняет от генерации перемещающего конструктора.
Кроме того, перемещающие операции не будут генерироваться для любого класса, у которого явно объявлены копирующие операции. Объяснение этому заключается в том, что объявление копирующих операций (конструктора и присваивания) указывает, что обычный подход к копированию объекта (почленное копирование) не годится для этого класса, и компиляторы делают заключение, что если для класса не подходит почленное копирование, то, вероятно, почленное перемещение для него тоже не подойдет.
Этот вывод справедлив и в обратном направлении. Объявление в классе перемещающей операции (конструктора или присваивания) приводит к тому, что компиляторы не генерируют копирующие операции. (Копирующие операции отключаются с помощью их удаления; см. раздел 3.5). В конце концов, если почленное перемещение не является корректным способом перемещения, то нет причин ожидать, что почленное копирование окажется корректным способом копирования. Это выглядит как возможное нарушение работоспособности кода С++98, поскольку условия, при которых разрешена генерация операций копирования, являются более ограничивающими в C++11, чем в С++98, но на самом деле это не так. Код С++98 не может иметь перемещающие операции, поскольку в С++98 нет такого понятия, как “перемещение” объектов. Единственный способ для старого класса иметь пользовательские перемещающие операции — это если они будут добавлены в коде С++11. Но классы, которые изменены таким образом, чтобы использовать преимущества семантики перемещений, обязаны играть по правилам С++11, касающимся генерации специальных функций-членов.
Вероятно, вы слышали о рекомендации о большой тройке . Она утверждает, что если вы объявили хотя бы одну из трех операций — копирующий конструктор, копирующий оператор присваивания или деструктор, — то вы должны объявить все три операции. Это правило вытекает из наблюдения, что необходимость изменения смысла копирующей операции почти всегда подразумевает, что (1) какое бы управление ресурсами не выполнялось в одной копирующей операции, вероятно, такое же управление ресурсами потребуется и во второй копирующей операции; и (2) деструктор класса также должен участвовать в управлении ресурсами (обычно — освобождать их). Классическим управляемым ресурсом является память, и именно поэтому все классы стандартной библиотеки, управляющие памятью (например, контейнеры STL, управляющие динамической памятью), объявляют всю “большую тройку”: обе копирующие операции и деструктор.
Читать дальшеИнтервал:
Закладка: