Обновления C++: подборка изменений из трех стандартов языка

2
8359
Добавить в избранное

Обновления C++, внесенные стандартами C++11, C++14 и C++17. Большая подборка нововведений самого языка и изменений стандартной библиотеки.

Обновления C++17

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

Теперь аргументы шаблонов автоматически выводятся не только для функций, но и для классов.

Объявление not-type шаблонных параметров с помощью auto

Если тип объекта входит в список not-type template, он может быть использован в качестве аргумента шаблона с помощью auto.

Выражения свертки

Поддерживается два типа свертки шаблонных параметров:

  • Унарная – выражения вида (... op e) или (e or …), где op – это оператор, а e – нераскрытая группа параметров.
  • Бинарная – выражения вида (e1 op … op e2), где либо e1, либо e2 (но не оба сразу) является нераскрытой группой параметров.

Новые правила вывода типа auto при фигурной инициализации

Изменился вывод auto при использовании универсального синтаксиса инициализации. Раньше для auto x{ 3 } тип выводился как std::initializer_list<int>, сейчас выводится int.

Constexpr лямбды

Лямбды, выполняющиеся во время компиляции, с использованием constexpr.

Захват this в лямбдах

Ранее захват this в лямбдах происходил только по ссылке. В C++17 *this теперь делает копию текущего объекта.

inline переменные

Спецификатор inline может применяться как к переменным, так и к функциям.

Вложенные пространства имен

Используйте оператор разрешения пространств имен для создания вложенных определений.

Структурированные привязки

В обновления C++17 входит новый синтаксис для деструктурирующей инициализации вида auto[ x,y,z ] = expr, где тип expr – это кортежеподобный объект. Подробнее о привязках вы можете узнать здесь.

Условные операторы с инициализацией

Новые версии инструкций if и switch позволяют упростить шаблоны кода.

constexpr if

Позволяет выполнять if-конструкции во время компиляции.

Символьные литералы UTF-8

Начинаются с u8 и имеют тип char. Значение символьного литерала UTF-8 равно его ISO 10646 значению.

Прямая инициализация списка перечислений

Перечисления теперь могут быть инициализированы с использованием braced-синтаксиса.

Обновления библиотеки С++17

std::variant

Типобезопасный union. В любой момент времени содержит значение одного из своих альтернативных типов (или вообще не имеет значения).

std::optional

Необязательное значение. Может использоваться в функциях или условиях.

 

std::any

Типобезопасный контейнер для единственного значения любого типа.

std::string_view

Ссылается на строку, но не владеет ей. Полезно для предоставления абстракции поверх строк (например, для синтаксического анализа).

std::invoke

Вызывает Callable объект (std::function или std::bind) с параметрами.

std::apply

Вызывает объект класса Callable с кортежем аргументов.

std::filesystem

Предоставляет стандартный способ управления файлами, каталогами и путями в файловой системе.
Пример копирования большого файла во временный путь:

std::byte

Обеспечивает стандартный способ представления данных в двоичном виде. В отличие от char или unsigned char доступны только побитовые операции.

std::byte — это просто перечисление, инициализация через фигурные скобки возможна благодаря прямой инициализации перечислений.

Манипуляции с мапами и множествами

Перемещения элементов и слияние контейнеров без затрат на создание копий и выделение/освобождение памяти.

Перемещение элементов из одного мапа в другой:

Вставка целого множества:

Вставка элементов без контейнера:

Изменение ключа элемента в мапе:

Параллельные алгоритмы

Многие из алгоритмов STL начали поддерживать политики параллельного выполнения: seq (последовательное), par (параллельное) и par_unseq (параллельное неупорядоченное).

Обновления C++14

Двоичные литералы

Удобный способ представления base-2 чисел с разделителем '.

Обобщенные лямбда-выражения

C++14 теперь позволяет использовать спецификатор типа auto в списке параметров, создавая полиморфные лямбды.

Инициализация лямбда-захватов

Позволяет создавать лямбда-захваты, инициализированные произвольными выражениями при создании лямбды.

Теперь можно захватывать move-only типы по значению. В примере ниже p в списке захвата task2 – это новая переменная.

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

Определение типа возвращаемого значения

При использовании типа auto для возвращаемого значения в C++14, компилятор попытается вывести тип самостоятельно.

decltype(auto)

Спецификатор типа decltype(auto) выводит тип, как auto, но сохраняет ссылки и CV-квалификаторы.

Ослабление ограничений для constexpr функций

Обновления C++14 этот значительно расширили набор конструкций, допустимых в constexpr функциях: добавились if-операторы, множественные return, циклы и т.д.

Шаблоны переменных

C++14 позволяет шаблонизировать переменные.

Обновления библиотеки C++14

Пользовательские литералы

Новые пользовательские литералы для типов стандартной библиотеки chrono и basic_string.

Целочисленные последовательности

std::integer_sequence представляет последовательности целых чисел.

  • std::make_integer_sequence<T, N...> — создает последовательности 0, ..., N - 1 с типом T.
  • std::index_sequence_for — преобразует пакет параметров шаблона в целочисленную последовательность.

Преобразование массива в кортеж:

std::make_unique

std::make_unique рекомендуется использовать для создания экземпляров std::unique_ptr, так как эта функция позволяет:

  • избежать использования оператора new;
  • предотвратить дублирование кода при указании базового типа, который должен содержать указатель;
  • обеспечить безопасность при исключениях.

Предположим, мы вызываем функцию foo следующим образом:

Поскольку мы выделили данные в куче в первой конструкции T, здесь происходит утечка. std::make_unique обеспечивает безопасность при выбросе исключений:

Обновления C++11

Семантика перемещения

Семантика перемещения связана с оптимизацией производительности – возможностью перемещения объекта без больших затрат на копирование.

Передача ресурсов, при которой они остаются на своем месте в памяти, полезна при работе с rvalue.

Перемещения также позволяют передавать объекты std::unique_ptr.

Ссылки rvalue

В C++11 появились новые ссылки rvalue с синтаксисом A&&.

Автоматическое определение типа со значениями lvalue и rvalue:

Шаблоны с переменным числом аргументов

Синтаксис ... создает пакет параметров или расширяет его. Шаблон с хотя бы одним пакетом параметров называется вариативным шаблоном.

Списки инициализации

Массивоподобные контейнеры элементов, созданные с использованием braced-синтаксиса. Например, { 1, 2, 3 } создает последовательность целых чисел с типом std:: initializer_list<int>.

Статические утверждения

Утверждения, вычисляемые во время компиляции.

auto

Переменные с типом auto выводятся компилятором в зависимости от типа их инициализатора.

Это существенно улучшает читаемость:

Функции также могут выводить возвращаемый тип с помощью auto.

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

Лямбда – это безымянные объекты функций, способные захватывать переменные в области видимости. У них есть список захвата (capture list):

  • []— ничего не захватывает.
  • [ = ]— захват локальных объектов по значению.
  • [ & ]— захват локальных объектов по ссылке.
  • [this] — захват указателя this по значению.
  • [a, &b] — захват объекта a по значению, b – по ссылке.

По умолчанию объекты, захваченные по значению, не могут быть изменены внутри лямбда-выражения, так как созданный компилятором метод помечен как const. Ключевое слово mutable позволяет изменять их.

decltype

decltype – оператор, возвращающий объявленный тип переданного ему выражения. CV-квалификаторы и ссылки сохраняются, если они являются частью выражения.

Псевдонимы шаблонов

Псевдонимы шаблонов семантически похожи на typedef, однако они легче читаются и совместимы с шаблонами.

nullptr

В C++11 появился новый тип null-указателя, предназначенный для замены макроса NULL языка C.

Строго типизированные перечисления

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

Атрибуты

Атрибуты создают универсальный синтаксис над __attribute__(...), __declspec и т. п.

constexpr

Выражения, которые вычисляются во время компиляции. В константном выражении могут выполняться только несложные вычисления.

Константные выражения с классами:

Делегирование конструкторов

Конструкторы теперь могут вызывать другие конструкторы в том же классе с помощью списка инициализаторов.

Пользовательские литералы

Пользовательские литералы позволяют расширить язык и добавить собственный синтаксис.

Преобразование Цельсия в градусы Фаренгейта:

Конвертация строки в целое число:

Явные замещения виртуальных функций

Указывает, что виртуальная функция переопределяет другую виртуальную функцию.

Спецификатор final

Указывает, что виртуальная функция не может быть переопределена в производном классе или, что класс не может быть от нее унаследован.

Функции по умолчанию

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

С наследованием:

Удаленные функции

Более элегантный и эффективный способ обеспечить удаленную реализацию функции. Полезно для предотвращения копирования объектов.

For-циклы по коллекциям

Синтаксический сахар для перебора элементов контейнера (range-based for).

Обратите внимание на разницу при использовании int, а не int&:

Специальные функции семантики перемещения

С введением семантики перемещения в C++11 теперь есть конструктор перемещения и перемещающий оператор присваивания.

Преобразование конструкторов

Преобразует braced list в аргументы конструктора.

Явные функции преобразования

Функции преобразования теперь можно сделать явными с помощью спецификатора explicit.

Встроенные пространства имен

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

Инициализаторы нестатических членов-данных

Позволяет инициализировать нестатические члены-данных там, где они объявлены.

Правые угловые скобки

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

Обновления библиотеки C++11

std::move

Указывает, что переданный объект может быть перемещен из одного объекта в другой без копирования.

Выполнение перемещения – это просто приведение аргумента к rvalue:

Передача std::unique_ptr:

std::forward

Может принимать на вход lvalue или rvalue и возвращать их как есть, без изменений, включает cv-квалификацию:

  • Т& & становится Т&;
  • Т& && становится Т&;
  • Т&& & становится Т&;
  • T&& && становится T&&;

Определение std:forward:

Пример функции wrapper, которая просто пересылает другие A объекты в новый конструктор копирования или перемещения объекта A:

std::thread

Библиотека std::thread предоставляет стандартный способ управления потоками.

std::to_string

Преобразует числовой аргумент в строку std::string.

Признаки типа

Признаки типа определяет интерфейс на основе шаблона времени компиляции для запроса или изменения свойств типов.

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

В обновления C++11 входят новые умные указатели: std::unique_ptr, std::shared_ptr, std::weak_ptr.

std:: chrono

Библиотека chrono содержит набор служебных функций и типов, которые имеют дело с длительностью, часами и временными точками.

Кортежи

Кортежи представляют собой наборы неоднородных значений фиксированного размера.

std::tie

Создает кортеж lvalue-элементов. Полезно для распаковки объектов std::pair и std::tuple.

std::array

std::array – это контейнер, построенный поверх C-подобных массивов. Поддерживает общие контейнерные операции, такие как сортировка.

Неупорядоченные контейнеры

Поддерживают среднюю постоянную сложность операций поиска, вставки и удаления. Есть четыре типа неупорядоченных контейнеров: unordered_set, unordered_multisetunordered_mapunordered_multimap.

std::make_shared

std::make_shared рекомендуется использовать для создания экземпляров std::shared_ptr, так как эта функция позволяет:

  • избежать использования оператора new;
  • предотвратить дублирование кода при указании базового типа, который должен содержать указатель;
  • обеспечить безопасность при исключениях;
  • предотвратить повторное выделение памяти.

Модель памяти

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

Обновления C++: подборка изменений из трех стандартов языка

Шпаргалки

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

Первая, с базовыми конструкциями и понятиями, хорошо подойдет для начинающих программистов C++:

Шпаргалка по C++ для начинающих

Pdf-версия здесь.

Вторая будет удобна для опытных разработчиков:

Шпаргалка по C++

Pdf-версия здесь.

Полезные ресурсы

  • cppreference – примеры и документация новых функций.
  • C++ Rvalue References Explained – большое вводное руководства по ссылкам rvalue, правильной пересылке и семантике перемещения.
  • Поддержка стандартов clang и gcc.
  • C++ Weekly – коллекция видеоуроков по C++.

Оригинальная статья: modern-cpp-features.

Другие статьи по C++

Интересуетесь программированием на C++?

Подпишитесь на нашу рассылку, чтобы получать больше интересных материалов:

И не беспокойтесь, мы тоже не любим спам. Отписаться можно в любое время.




2 Комментарии

Оставьте комментарий