Скотт Мейерс - Эффективный и современный С++. 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, поскольку он посвящен тому, как уговорить компилятор это сделать.
Интервал:
Закладка: