Скотт Мейерс - Эффективный и современный С++. 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 - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Важно понимать, что const(и volatile) игнорируются только параметрами, передаваемыми по значению. Как мы уже видели, для параметров, которые являются ссылками или указателями на const, константность exprпри выводе типа сохраняется. Но рассмотрим случай, когда exprпредставляет собой const-указатель на константный объект, а передача осуществляется по значению:
template
void f( Тparam); // param передается по значению
const char* const ptr = // ptr - константный указатель на
"Fun with pointers"; // константный объект
f(ptr); // Передача arg типа const char* const
Здесь constсправа от звездочки объявляет ptrконстантным: ptrне может ни указывать на другое место в памяти, ни быть обнуленным. ( constслева от звездочки гласит, что ptrуказывает на то, что (строка символов) является const, а следовательно, не может быть изменено.) Когда ptrпередается в функцию f, биты, составляющие указатель, копируются в param. Как таковой сам указатель ( ptr ) будет передан по значению . В соответствии с правилом вывода типа при передаче параметров по значению константность ptrбудет проигнорирована, а выведенным для paramтипом будет const char*, т.е. изменяемый указатель на константную строку символов. Константность того, на что указывает ptr, в процессе вывода типа сохраняется, но константность самого ptrигнорируется при создании нового указателя param.
Мы рассмотрели большую часть материала, посвященного выводу типов шаблонов, но есть еще один угол, в который стоит заглянуть. Это отличие типов массивов от типов указателей, несмотря на то что зачастую они выглядят взаимозаменяемыми. Основной вклад в эту иллюзию вносит то, что во множестве контекстов массив преобразуется в указатель на его первый элемент. Это преобразование позволяет компилироваться коду наподобие следующего:
const char name[] = "Briggs"; // Тип name - const char[13]
const char * ptrToName = name; // Массив становится указателем
Здесь указатель ptrToNameтипа const char*инициализируется переменной name, которая имеет тип const char[13].Эти типы ( const char*и const char[13]) не являются одним и тем же типом, но благодаря правилу преобразования массива в указатель приведенный выше код компилируется.
Но что будет, если передать массив шаблону, принимающему параметр по значению?
template
void f(T param); // Шаблон, получающий параметр по значению
f(name); // Какой тип Т и param будет выведен?
Начнем с наблюдения, что не существует такой вещи, как параметр функции, являющийся массивом. Да, да — приведенный далее синтаксис корректен:
void myFunc(int param []);
Однако объявление массива рассматривается как объявление указателя, а это означает, что функция myFunc может быть эквивалентно объявлена как
void myFunc(int *param); // Та же функция, что и ранее
Эта эквивалентность параметров, представляющих собой массив и указатель, образно говоря, представляет собой немного листвы от корней С на дереве С++ и способствует возникновению иллюзии, что типы массивов и указателей представляют собой одно и то же.
Поскольку объявление параметра-массива рассматривается так, как если бы это было объявление параметра-указателя, тип массива, передаваемого в шаблонную функцию по значению, выводится как тип указателя. Это означает, что в вызове шаблонной функции fее параметр типа Твыводится как const char*:
f(name); // nаmе - массив, но Т - const char*
А вот теперь начинаются настоящие хитрости. Хотя функции не могут объявлять параметры как истинные массивы, они могут объявлять параметры, являющиеся ссылками на массивы! Так что если мы изменим шаблон fтак, чтобы он получал свой аргумент по ссылке,
template
void f( T¶m); // Шаблон с передачей параметра по ссылке
и передадим ему массив
f(name); // Передача массива функции f
то тип, выведенный для Т, будет в действительности типом массива! Этот тип включает размер массива, так что в нашем примере Твыводится как const char[13], а типом параметра f(ссылки на этот массив) является const char (&)[13]. Да, выглядит этот синтаксис как наркотический бред, но знание его прибавит вам веса в глазах понимающих людей.
Интересно, что возможность объявлять ссылки на массивы позволяет создать шаблон, который выводит количество элементов, содержащихся в массиве:
// Возвращает размер массива как константу времени компиляции.
// Параметр не имеет имени, поскольку, кроме количества
// содержащихся в нем элементов, нас ничто не интересует.
template
constexpr std::size_t arraySize( T (&)[N]) nоехсерt {
return N;
}
Как поясняется в разделе 3.9, объявление этой функции как constexprделает ее результат доступным во время компиляции. Это позволяет объявить, например, массив с таким же количеством элементов, как и у второго массива, размер которого вычисляется из инициализатора в фигурных скобках:
// keyVals содержит 7 элементов:
int keyVals[] = { 1, 3, 7, 9, 11, 22, 35 };
int mappedVals[ arraySize(keyVals)]; // mappedVals - тоже
Конечно, как разработчик на современном С++ вы, естественно, предпочтете std::arrayвстроенному массиву:
// Размер mappedVals равен 7
std::arrayarraySize(keyVals)> mappedVals;
Что касается объявления arraySizeкак noexcept, то это помогает компилятору генерировать лучший код. Детальнее этот вопрос рассматривается в разделе 3.8.
Массивы — не единственные сущности в С++, которые могут превращаться в указатели. Типы функций могут превращаться в указатели на функции, и все, что мы говорили о выводе типов для массивов, применимо к выводу типов для функций и их преобразованию в указатели на функции. В результате получаем следующее:
void someFunc(int, double); // someFunc - функция;
// ее тип - void (int, double)
template
void f1(Т param); // В f1 param передается по значению
template
void f2(T& param); // В f2 param передается по ссылке
f1(someFunc); // param выводится как указатель на
// функцию; тип - void (*)(int, double)
f2(someFunc); // param выводится как ссылка на
// функцию; тип - void(&)(int,double)
Это редко приводит к каким-то отличиям на практике, но если вы знаете о преобразовании массивов в указатели, то разберетесь и в преобразовании функций в указатели.
Итак, у нас есть правила для вывода типов шаблонов, связанные с auto. В начале я заметил, что они достаточно просты, и по большей части так оно и есть. Немного усложняет жизнь отдельное рассмотрение согласованных lvalue при выводе типов для универсальных ссылок, да еще несколько “мутят воду” правила преобразования в указатели для массивов и функций. Иногда так и хочется, разозлившись, схватить компилятор и вытрясти из него — “А скажи-ка, любезный, какой же тип ты выводишь?” Когда это произойдет, обратитесь к разделу 1.4, поскольку он посвящен тому, как уговорить компилятор это сделать.
Интервал:
Закладка: