Найти тему
Nuances of programming

Возможности C++, о которых должен знать каждый разработчик

Оглавление

Источник: Nuances of Programming

С момента своего появления C++ очень хорошо развился как язык программирования.

Конечно, это не произошло моментально. Когда-то этому языку не доставало динамичности. В то время было довольно сложно пользоваться им.

Но всё изменилось, когда комитет по стандартизации C++ решил, что нужно двигаться вперёд.

С 2011 года C++ стал популярным динамическим современным языком программирования.

Не думайте, что язык стал проще. Он до сих пор является одним из самых сложных языков программирования, если не самым сложным из широко используемых. Но, определённо, он стал гораздо проще своих предыдущих версий.

В этой статье мы рассмотрим новые функции этого языка (начиная с C++11, которому уже восемь лет), о которых должен знать каждый разработчик.

Ключевое слово auto

Жизнь стала гораздо проще, когда в C++11 появилось ключевое слово auto.

Суть этого ключевого слова в том, что оно даёт возможность автоматически определять тип данных на этапе компиляции программы. То есть, вам не нужно каждый раз объявлять, какого типа та или иная переменная. Это очень удобно при объявлении типов данных вроде map<string,vector<pair<int,int>>>.

-2

Обратите внимание на пятую строчку. Вы не можете объявить переменную таким образом без её инициализации. Логично. Компилятор не знает, какой тип данных вы будете использовать для этой переменной.

Изначально возможности auto были довольно ограничены, но с каждой новой версией языка они расширяются.

-3

В седьмой и восьмой строчке при инициализации вектора используются скобки. Это новая функция, добавленная в C++11.

Не забывайте, что при использовании auto необходимо оставлять подсказки для компилятора для определения типа данных.

А теперь интересный вопрос: что произойдет, если мы напишем auto a = {1, 2, 3}? Компилятор выдаст ошибку? Или определит тип как vector?

-4

В C++11 появился новый тип данных std::initializer_list<type>. При использовании для декларации переменной ключевого слова auto и инициализации списка при помощи скобок будет использоваться этот контейнер.

И последнее: как я упомянул ранее, использование этого ключевого слова крайне полезно, если у вас сложные структуры данных:

-5

Обратите внимание на 25 строчку! Выражение auto [v1,v2] = itr.second — новая функция C++17. Такие выражения называются структурными привязками. В предыдущих версиях языка нужно было получать значение для каждой переменной отдельно. Теперь же структурные привязки позволяют делать это более удобным способом.

К тому же, если вы хотите получить данные при помощи ссылки, нужно лишь добавить амперсанд ( &): auto &[v1,v2] = itr.second.

Лямбда-выражения

В C++11 появились лямбда-выражения. Они похожи на анонимные функциональные выражения в JavaScript. Это безымянные функции, для которых можно определять видимость переменных. Также их можно присваивать переменным.

Лямбда-выражения полезны, если вам нужно сделать что-то внутри вашего кода, но создание для этого отдельной функции усложнит программу. Довольно часто они используются как функции-компараторы.

-6

В примере выше есть достаточно много моментов, которые стоит упомянуть.

Во-первых, заметьте, как инициализация вектора при помощи фигурных скобок упрощает жизнь. Затем идут обобщённые функции begin() и end(), которые, к слову, тоже появились лишь в C++11. Потом в качестве компаратора передаётся лямбда-выражение. Типы параметров функции задаются ключевым словом auto, которое появилось в C++14. До этого мы не могли использовать его для параметров функции.

Обратите внимание на то, что мы начинаем лямбда-выражение с квадратных скобок []. Они определяют область видимости нашей функции — авторитет функции над локальными переменными и объектами.

Как определено в репозитории C++:

  • [] — внутри функции вы можете использовать только параметры, локальные переменные не будут видны.
  • [=] — позволяет использовать значения локальных объектов внутри функции, но не позволяет их изменять.
  • [&] — позволяет как использовать, так и менять локальные объекты.
  • [this] — передаёт указатель this как значение.
  • [a, &b] — передаёт объект a как значение и объект bкак ссылку.

Таким образом, если вы хотите менять уже существующие данные внутри лямбда-выражения, установите её авторитет над локальными объектами. Например:

-7

В примере выше, если бы вы передали локальную переменную по значению ([factor]), то в пятой строчке вы не смогли бы изменить её значение. У вас просто-напросто нет прав на это. Помните о своих правах!

Заметьте, что параметр функции val — ссылка на объект. Таким образом, мы будем уверены в том, что лямбда-выражение действительно изменит вектор.

Они несказанно рады тому, что узнали об этих возможностях C++!
Они несказанно рады тому, что узнали об этих возможностях C++!

init внутри if и switch

Эта возможность C++17 мне полюбилась сразу же, как только я узнал о ней.

-9

Теперь вы можете инициализировать переменные и проверять условия сразу же внутри блоков if и switch. Это помогает сохранять код понятным и чистым. Общий синтаксис таков:

-10

Сделай это при компиляции: constexpr

constexpr — это классно!

Допустим, у вас есть выражение, значение которого нужно вычислить и которое не будет меняться после этого. Вы можете вычислить значение заранее и использовать его как макрос. Или, как предлагает C++11, вы можете использовать constexpr.

Программисты сокращают время работы программы насколько возможно. Например, некоторые операции перекладываются на компилятор.

-11

Код выше — довольно частый пример использования constexpr.

Так как мы объявили функцию вычисления чисел Фибоначчи как constexpr, компилятор вычислит значение fib(20) во время компиляции. Тогда после компиляции строка const long long bigval = fib(20); будет заменена на const long long bigval = 2432902008176640000;

Заметьте, что передаваемый аргумент имеет квалификатор const. Это один из немаловажных моментов использования функций с флагом constexpr. Аргументы такой функции также должны быть constexpr или const. В противном случае функция будет вести себя, как совершенно обыкновенная, то есть, вычисления не будут выполнены во время компиляции.

Спецификатор constexpr может применяться и к переменным. В этом случае переменная должна однозначно вычисляться во время компиляции, или программа выдаст ошибку компиляции.

Кстати, в C++17 появились ещё и такие ключевые слова, как constexpr-if и constexpr-lambda.

Кортеж — tuple

Как и pair, tuple — коллекция значений различных типов данных конкретного размера.

-12

В некоторых случаях вместо tuple удобнее использовать std::array. Это обычный массив с некоторыми функциями стандартной библиотеки C++, который был добавлен в C++11.

Вывод параметра шаблона класса

Довольно странное название функции, да? Её суть в том, что с C++17 компилятор может сам определять типы аргументов конструкторов стандартных классов. Раньше же это работало лишь для функций.

std::pair<std::string, int> user = {“M”, 25}; // раньше
std::pair user = {“M”, 25};
// C++17

Для кортежей всё становится ещё проще:

// раньше
std::tuple<std::string, std::string, int> user (“M”, “Chy”, 25);
// предугадывание в действии!
std::tuple user2(“M”, “Chy”, 25);

Для того, чтобы осознать удобство этой функции, нужно быть знакомыми с конструкторами классов в C++.

Умные указатели

Указатели могут быть ужасны.

Из-за свободы, которую вам даёт C++, довольно часто бывает удивительно легко загнать себя в ловушку. И во многих случаях в этом виноваты указатели.

К счастью, в C++11 появились умные указатели. Работать с ними на порядок удобнее, нежели с обычными указателями. Они предотвращают утечку памяти, так как сами освобождают себя, если они не нужны. К тому же они обеспечивают устойчивость к исключениям.

Я хотел бы написать ещё больше об умных указателях, но я не умещу здесь все важные детали.

Это всё на сегодня. С каждой версией в C++ появляются новые функции. Если вам интересно, можете узнать о них больше в этом репозитории.

Читайте нас в телеграмме и vk

Перевод статьи M Chowdhury: Some awesome modern C++ features that every developer should know