Скотт Мейерс - Эффективный и современный С++. 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 - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
• В процессе вывода типа шаблона аргументы, являющиеся ссылками, рассматриваются как ссылками не являющиеся, т.е. их “ссылочность” игнорируется.
• При выводе типов для параметров, являющихся универсальными ссылками, lvalue-apгумeнты рассматриваются специальным образом.
• При выводе типов для параметров, передаваемых по значению, аргументы, объявленные как const
и/или volatile
, рассматриваются как не являющиеся ни const
, ни volatile
.
• В процессе вывода типа шаблона аргументы, являющиеся именами массивов или функций, преобразуются в указатели, если только они не использованы для инициализации ссылок.
1.2. Вывод типа auto
Если вы прочли раздел 1.1 о выводе типов шаблонов, вы знаете почти все, что следует знать о выводе типа auto
, поскольку за одним любопытным исключением вывод типа auto
представляет собой вывод типа шаблона. Но как это может быть? Вывод типа шаблона работает с шаблонами, функциями и параметрами, а auto
не имеет дела ни с одной из этих сущностей.
Да, это так, но это не имеет значения. Существует прямая взаимосвязь между выводом типа шаблона и выводом типа auto
. Существует буквальное алгоритмическое преобразование одного в другой.
В разделе 1.1 вывод типа шаблона пояснялся с использованием обобщенного шаблона функции
templateТ>
void f( ParamType param);
и обобщенного вызова
f( expr ); // Вызов f с некоторым выражением
При вызове f
компиляторы используют expr
для вывода типов T
и ParamType
.
Когда переменная объявлена с использованием ключевого слова auto
, оно играет роль Т
в шаблоне, а спецификатор типа переменной действует как ParamType
. Это проще показать, чем описать, так что рассмотрим следующий пример:
autox = 27;
Здесь спецификатором типа для x
является auto
само по себе. С другой стороны, в объявлении
const autocx = x;
спецификатором типа является const auto
. А в объявлении
const auto&rx = x;
спецификатором типа является const auto&
. Для вывода типов для x
, сх
и rx
в приведенных примерах компилятор действует так, как если бы для каждого объявления имелся шаблон, а также вызов этого шаблона с соответствующим инициализирующим выражением:
template // Концептуальный шаблон для
void func_for_x(Т param); // вывода типа x
func_for_x(27); // Концептуальный вызов: выве-
// денный тип param является
// типом x
template // Концептуальный шаблон для
void func_for_cx(const Т param); // вывода типа cx
func_for_cx(x); // Концептуальный вызов: выве-
// денный тип param является
// типом cx
template // Концептуальный шаблон для
void func_for_rx(const T& param); // вывода типа rx
func_for_rx(x); // Концептуальный вызов: выве-
// денный тип param является
// типом rx
Как я уже говорил, вывод типов для auto
представляет собой (с одним исключением, которое мы вскоре рассмотрим) то же самое, что и вывод типов для шаблонов.
В разделе 1.1 вывод типов шаблонов был разделен на три случая, основанных на характеристиках ParamType
, спецификаторе типа param
в обобщенном шаблоне функции. В объявлении переменной с использованием auto
спецификатор типа занимает место ParamType
, так что у нас опять имеются три случая.
• Случай 1. Спецификатор типа представляет собой ссылку или указатель, но не универсальную ссылку.
• Случай 2. Спецификатор типа представляет собой универсальную ссылку.
• Случай 3. Спецификатор типа не является ни ссылкой, ни указателем. Мы уже встречались со случаями 1 и 3:
autox = 27; // Случай 3 (x не указатель и не ссылка)
const autocx = x; // Случай 3 (cx не указатель и не ссылка)
const auto&rx = x; // Случай 1 (rx - неуниверсальная ссылка)
Случай 2 работает, как и ожидалось:
auto&&uref1 = x; // x - int и lvalue, так что тип uref1 – int&
auto&&uref2 = cx; // cx - const int и lvalue, так что тип
// uref2 - const int&
auto&&uref3 = 27; // 27 - int и rvalue, так что тип
// uref3 - int&&
Раздел 1.1 завершился обсуждением того, как имена массивов и функций превращаются в указатели для спецификаторов типа, не являющихся ссылками. То же самое происходит и при выводе типа auto
:
const char name[] = // Тип name - const char [13]
"R. N. Briggs";
autoarr1 = name; // Тип arr1 - const char*
auto&arr2 = name; // Тип arr2 - const char (&)[13]
void someFunc(int, double); // someFunc - функция, ее тип
// void(int, double)
autofunc1 = someFunc; // Тип func1 - void (*)(int, double)
auto&func2 = someFunc; // Тип func2 - void (&)(int, double)
Как можно видеть, вывод типа auto
работает подобно выводу типа шаблона. По сути это две стороны одной медали.
Они отличаются только в одном. Начнем с наблюдения, что если вы хотите объявить int
с начальным значением 27, С++98 предоставляет вам две синтаксические возможности:
intx1 = 27;
intx2(27);
С++11, поддерживая старые варианты инициализации, добавляет собственные:
intx3 = { 27 };
intx4{ 27 };
Таким образом, у нас есть четыре разных синтаксиса, но результат один: переменная типа int
со значением 27.
Но, как поясняется в разделе 2.1, объявление переменных с использованием ключевого слова auto
вместо фиксированных типов обладает определенными преимуществами, поэтому в приведенных выше объявлениях имеет смысл заменить int
на auto
. Простая замена текста приводит к следующему коду:
autox1 = 27;
autox2(27);
autox3 = { 27 };
autox4{ 27 };
Все эти объявления компилируются, но их смысл оказывается не тем же, что и у объявлений, которые они заменяют. Первые две инструкции в действительности объявляют переменную типа int
со значением 27. Вторые две, однако, определяют переменную типа std::initializer_list
, содержащую единственный элемент со значением 27!
auto x1 = 27; // Тип int, значение - 27
auto x2(27); // То же самое
auto x3 = { 27 }; // std::initializer_list, значение (27}
auto x4{ 27 }; // То же самое
Это объясняется специальным правилом вывода типа для auto
. Когда инициализатор для переменной, объявленной как auto
, заключен в фигурные скобки, выведенный тип — std::initializer_list
. Если такой тип не может быть выведен (например, из-за того, что значения в фигурных скобках относятся к разным типам), код будет отвергнут:
auto x5 = { 1, 2, 3.0}; // Ошибка! Невозможно вывести Т
// для std::initializer_list
Как указано в комментарии, в этом случае вывод типа будет неудачным, но важно понимать, что на самом деле здесь имеют место два вывода типа. Один из них вытекает из применения ключевого слова auto
: тип x5
должен быть выведен. Поскольку инициализатор x5
находится в фигурных скобках, тип x5
должен быть выведен как std::initializer_list
. Но std::initializer_list
— это шаблон. Конкретизация представляет собой создание std::initializer_list
с некоторым типом Т
, а это означает, что тип Т
также должен быть выведен. Такой вывод относится ко второй разновидности вывода типов — выводу типа шаблона. В данном примере этот второй вывод неудачен, поскольку значения в фигурных скобках не относятся к одному и тому же типу.
Интервал:
Закладка: