WikiSort.ru - Программирование

ПОИСК ПО САЙТУ | о проекте

С++17 (также известный как C++1z) — это название версии стандарта C++ ISO/IEC. Спецификации для C++17 были опубликованы в декабре 2017 года[1][2].

Возможности

  • Новые методы вставки для std::map и std::unordered_map[3][4];
  • Унифицированный доступ к размеру контейнеров[4][5] std::size();
  • Библиотека файловой системы, основанная на boost::filesystem[6];
  • Параллельные версии алгоритмов STL[7];
  • Некоторые математические функции[8];
  • Большую часть экспериментальной библиотеки TS I[9].
  • Новый синтаксис для распаковки пар, кортежей и прочих типов, для которых реализован std::get. Например: auto x = std::make_tuple(4,6,7); auto [a,b,c] = x;
  • Инициализация переменной в if и switch. Например: if(auto a = getA(); a.isValid()) {}
  • Автоматический вывод аргументов шаблона класса; также поддерживается ручное указание правил вывода.

Удалены или запрещены

Удалены триграфы

Триграфы использовались для машин с нестандартной кодировкой и/или ограниченной клавиатурой. Ещё в конце 80-х, с распространением 8-битных кодировок и дешёвых резиномембранных клавиатур, триграфы фактически потеряли смысл, и тридцать лет спустя были закономерно исключены[10][11].

// Will the next line be executed????????????????/
a++;      /* с триграфами эта строка закомментирована — триграф ??/ эквивалентен \ */

Лишено смысла ключевое слово register

Язык Си был «переносимым ассемблером»: он позволял делать быстрые программы, компилирующиеся на разных компьютерах, к тому же использовал ассемблерные утилиты (компоновщик, библиотекарь). Понятия вроде «заголовочный файл» и «единица трансляции» — отголоски тех времён.

Слово register изначально связанно с ручной оптимизацией программы. Слово всё ещё остаётся зарезервированным, но не означает ничего[12].

Удалена операция ++ для bool

Операция явно небезопасна и запрещена ещё в Си++98[13]. Операция -- отсутствует и так.

Удалены заявленные исключения

Заявленные исключения void f() throw(A, B, C);, имеющиеся, например, в Java, приносят больше вреда, чем пользы. Запрещены в Си++11, удалены в Си++17. Остался throw() как синоним для noexcept(true)[14].

Запретили повторное объявление constexpr-переменных

Код struct X {static constexpr int n = 10;}; int X::n; явно избыточен, но почему-то был разрешён. Функциональность constexpr аналогична новым inline-переменным[15].

Удалены типы и функции, получившие замену (и ставшие запрещёнными) в Си++11

В их числе std::auto_ptr, std::random_shuffle и старые функциональные адаптеры[16][17].

Вместо них используются unique_ptr, shuffle и новые функциональные шаблоны, основанные на function/bind. Заявляется, что любой код на auto_ptr может быть механически преобразован в unique_ptr, с простым добавлением std::move там, где идёт передача владения.

Также удалены отдельные части iostream, запрещённые ещё в Си++98[18].

Удалены конструкторы для std::function, принимавшие аллокатор

Всего пять перегрузок, включая эту

template< class Alloc >
function( std::allocator_arg_t, const Alloc& alloc ) noexcept;

Из-за непонятной семантики и сложностей реализации их удалили без предварительного запрета[19].

Запрещены крайне редкие возможности стандартной библиотеки

Запрещены несколько редких возможностей стандартной библиотеки:[20][21][22]

  • allocator<void> — оказался невостребованным;
  • часть функций allocator — дублируются allocator_traits;
  • raw_storage_iterator — не вызывает конструкторов и потому ограничен по применению;
  • get_temporary_buffer — имеет неочевидные подводные камни;
  • is_literal_type — бесполезен для обобщённого кода, но оставлен, пока в Си++ существует понятие «литеральный тип»;
  • iterator — проще писать итераторы с нуля, чем основываться на нём;
  • codecvt — на поверку работал очень плохо, комитет призвал пользоваться специализированными библиотеками;
  • shared_ptr::unique() — из-за ненадёжности в многопоточной среде.

Полностью удалить обещают в Си++20.

Запреты, связанные с новыми функциями Си++17

  • result_ofinvoke_result — более простой синтаксис, основанный на выведении типов Си++11[23];
  • bool uncaught_exception()int uncaught_exceptions() — когда пользователь, например, выдернул флэшку и начали «сыпаться» аварии, может «висеть» необработанными и несколько исключений[24][25].

Временно запрещён memory_order_consume

Из-за неадекватной семантики метод упорядочивания «consume» временно запретили, призвав пользоваться методом «acquire». Работа над новой семантикой всё ещё ведётся и, возможно, запрет когда-нибудь снимут[26].

Удалены хедеры библиотеки Си

С переходом на Си11 удалены заголовочные файлы <ccomplex>, <cstdalign>, <cstdbool>, <ctgmath>. Файл <ciso646> не запрещён[27].

Глобальные изменения

Спецификация исключений теперь часть системы типов

Функции void f() noexcept(true); и void f() noexcept(false); — теперь функции с разными типами (но не могут формировать перегруженный набор). Это позволит API требовать callback’и, которые не выбрасывают аварий[28].

New с чрезмерным выравниванием

В Си++11 появилась возможность создавать структуры данных, чьё выравнивание больше, чем теоретическое. Эта возможность была подхвачена операцией new[29].

class alignas(16) float4 {
	float f[4];
};
float4 *p = new float4[1000];

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

Обязательное избавление от копирования

Изменён смысл понятия prvalue: теперь это всего лишь инициализация.

В коде SomeType a = 10; хоть всё ещё требуется и конструктор, и операция =, гарантированно будет вызван только конструктор.

Это значит, что функции могут возвращать типы, которые нельзя копировать и перемещать.

Более строгий порядок вычисления

Теперь операции a.b, a->b, a->*b, a(b1, b2, b3), b += a (и аналоги для других операций), a[b], a << b и a >> b вычисляются в порядке a → b, чтобы держать под контролем побочные эффекты[30].

Если их вызвать как функции (например, operator += (a, b)), порядок остаётся неопределённым.

Расширили понятие «константа в шаблоне»

Существуют шаблоны, принимающие константу.

template <int N> struct Array
{
  int a[N];
};

Что может быть константой N, и что не может — объявлено от противного. Константа в шаблоне не может быть указателем на поле, временный объект, строковый литерал, результат typeid и стандартную переменную __func__[25][31];

В for могут быть begin и end разного типа

Теперь for (auto v : x) означает auto __begin = begin-expr; auto __end = end-expr;, позволяя begin и end разных типов.

Это — база для прохода по диапазонам (ranges), работа над которыми продолжается[32].

Редакционные правки

Понятие «непрерывный итератор»

Массивы std::vector и std::string имеют дело с непрерывными участками памяти. Для них ввели понятие «непрерывный итератор»[4][33]. Концептуально ничего не изменилось.

Запрещены символы u'x' и U'x', не кодируемые одним символом

Ранее подобное поведение определялось реализацией.

Заодно сделали «символы UTF-8», которые имеют тип char и могут держать коды от 0 до 255, по аналогии со строками UTF-8 — по видимому, чтобы программа меньше зависела от настроек локали на компьютере[25][34].

Язык

static_assert с одним аргументом

Если static_assert не сработал, не всегда требуется сообщать программисту, что не так — часто он и сам может понять из констекста.[35].

static_assert(sizeof(wchar_t) == 2);

Новые стандартные атрибуты

  • [[fallthrough]]: в одном из разделов оператора switch мы намеренно «проваливаемся» в следующий.
  • [[nodiscard]]: вызов функции как процедуры считается ошибкой — например, это «чистая» функция вроде string::empty()[36], вся работа которой заключается в возврате значения, или протокол работы с объектом требует что-то сделать с возвращённым значением, как в unique_ptr::release().
  • [[maybe_unused]]: в каком-то из режимов компиляции (Windows/POSIX, отладка/выпуск) тот или иной элемент не используется, и это не ошибка.

Использование typename во вложенных шаблонах

Недоработка языка Си++: в шаблонах typename и class кое-где не взаимозаменяемые[37].

template<template<typename> class X> struct C;    // OK
template<template<typename> typename X> struct D; // не компилируется

Оба ключевых слова явно объявлены взаимозаменяемыми.

auto x{}; больше не создаёт initializer_list

Добавленный в Си++11 универсальный инициализатор int x{}; позволяет одним синтаксисом создать объект, структуру, массив. В Си++17 уточнено: если вместо типа стоит auto — пользователь хочет создать один объект и никаких initializer_list не нужно.

При этом auto x = {1, 2, 3}; продолжает создавать: с одной стороны, для совместимости с for (auto x : {1, 2, 3}), с другой — для одного объекта есть auto x = 1;[38][17].

auto x1 = { 3 };   // std::initializer_list<int>
auto x2 { 1, 2 };  // теперь ошибка
auto x3 { 3 };     // int

Запись namespace A::B

Определение вложенных пространств имён:[17][39] namespace A::B {} как сокращение для namespace A { namespace B {} };

Атрибуты для пространств имён и элементов перечисляемого типа

Например:

enum class TriBool {
  NO,
  MAYBE,
  YES,
  NN [[maybe_unused]]
};
constexpr int TriBool_N = static_cast<int>(TriBool::NN);
const char* triBoolNames[TriBool_N] = { "no", "maybe", "yes" };

Какой-то заявленной цели пока нет[25][40], но это позволит разработчикам компиляторов придумать таковую — например, объявить, что элемент NN особый и его не надо присваивать переменным, обрабатывать в switch.

If при компиляции

Концепция SFINAE позволила сделать несложный шаблон enable_if, который обеспечивает разную функциональность для разных типов, но даёт тяжеловесный код. В Си++17 можно упростить программу: оператор if constexpr(expression) инстанцирует код, если выражение в скобках истинно[41].

template <class T>
constexpr T absolute(T arg) {
  return arg < 0 ? -arg : arg;
}

template <class T>
constexpr auto precision_threshold = T(0.000001);

template <class T>
constexpr bool close_enough(T a, T b) {
  if constexpr (is_floating_point_v<T>) // << !!
    return absolute(a - b) < precision_threshold<T>;
  else
    return a == b;
}

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

Упрощённый синтаксис двухместной операции в переменных шаблонах

Упакованные выражения[25][42]:

template<typename... As> void foo(As... args)
    { return (args && ...); }

Библиотека

Поддержка C11

Языки Си и Си++ разрабатываются разными комитетами. Стандартную библиотеку обновили с C99 до C11[43].

Новый тип string_view

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

void doSmth(const char *s);
void doSmth(const std::string &s);

Если методика владения памятью другая, приходится проводить преобразование.

В C++17 появился тип string_view — строка, имеющая только указатель и длину, без владения и управления памятью.

Размер строки кэша

Есть две новые константы, hardware_constructive_interference_size и hardware_destructive_interference_size. Таким образом пользователь может избежать ложного общего доступа (destructive interference) и улучшить локальность (constructive interference).

struct keep_apart {
  alignas(hardware_destructive_interference_size) atomic<int> cat;
  alignas(hardware_destructive_interference_size) atomic<int> dog;
  // cat далеко от dog, их можно менять из разных потоков.
};

struct together {
  atomic<int> dog;
  int puppy;
};
struct kennel {
  //...
  alignas(sizeof(together)) together pack;
  //...
};
static_assert(sizeof(together) <= hardware_constructive_interference_size);
// убеждаемся, что together занимает одну строку кэша.

Теоретически обе константы должны быть одинаковыми, но для поддержки неоднородных архитектур решено было сделать две константы.[44]

Автоматическое определение типа параметра контейнера

В библиотеке появились функции, так называемые deduction guides, позволяющие делать такое:

std::pair p(2, 4.5);   // 1

std::vector<int> v = {1, 2, 3, 4};
std::vector x(v.begin(), v.end());   // 2

См. также

Ссылки

  • Черновик стандарта, N4659, от 21.03.2017

Примечания

  1. ISO/IEC 14882:2017.
  2. Recent milestones: C++17 nearly feature-complete, second round of TSes now under development
  3. N4279: Improved insertion interface for unique-key maps (Thomas Köppe).
  4. 1 2 3 New standard library papers adopted for C++17.
  5. N4280: Non-member size() and more (Riccardo Marcangelo).
  6. Filesystem Library Proposal (Beman Dawes).
  7. The Parallelism TS Should be Standardized.
  8. Mathematical Special Functions for C++17, v5.
  9. Adopt Library Fundamentals V1 TS Components for C++17 (R1).
  10. N3981: Removing trigraphs??! (Richard Smith) (6 мая 2014).
  11. IBM comment on preparing for a Trigraph-adverse future in C++17, IBM paper N4210, 2014-10-10.
  12. Remove Deprecated Use of the register Keyword.
  13. Remove Deprecated operator++(bool).
  14. Removing Deprecated Exception Specifications from C++17.
  15. Inline Variables.
  16. N4190: Removing auto_ptr, random_shuffle(), And Old <functional> Stuff (Stephan T. Lavavej).
  17. 1 2 3 Updates to my trip report.
  18. Remove Deprecated iostreams aliases.
  19. Removing Allocator Support in std::function (rev 1).
  20. Deprecating Vestigial Library Parts in C++17.
  21. Deprecating <codecvt>.
  22. Proposed Resolution for CA 14 (shared_ptr use_count/unique).
  23. Resolving GB 55, US 84, US 85, US 86.
  24. N4259: Wording for std::uncaught_exceptions (Herb Sutter).
  25. 1 2 3 4 5 New core language papers adopted for C++17.
  26. Temporarily discourage memory_order_consume.
  27. C++17 should refer to C11 instead of C99.
  28. Make exception specifications be part of the type system.
  29. Dynamic memory allocation for over-aligned data.
  30. [http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0145r3.pdf Refining Expression Evaluation Order for Idiomatic C++].
  31. N4268: Allow constant evaluation for all non-type template arguments (Richard Smith).
  32. Generalizing the Range-Based For Loop.
  33. N4284: Contiguous Iterators (Jens Maurer).
  34. N4267: Adding u8 character literals (Richard Smith).
  35. N3928: Extending static_assert, v2 (Walter E. Brown).
  36. Так, авторы PVS-Studio часто жаловались на ошибку: программист вместо clear() писал empty().
  37. N4051: Allow typename in a template template parameter (Richard Smith).
  38. N3922: New Rules for auto deduction from braced-init-list (James Dennett).
  39. N4230: Nested namespace definition (Robert Kawulak, Andrew Tomazos).
  40. N4266: Attributes for namespaces and enumerators (Richard Smith).
  41. constexpr if: A slightly different syntax.
  42. N4295: Folding expressions (Andrew Sutton, Richard Smith).
  43. C++17 should refer to C11 instead of C99.
  44. P0154R1 constexpr std::hardware_{constructive,destructive}_interference_size.

Данная страница на сайте WikiSort.ru содержит текст со страницы сайта "Википедия".

Если Вы хотите её отредактировать, то можете сделать это на странице редактирования в Википедии.

Если сделанные Вами правки не будут кем-нибудь удалены, то через несколько дней они появятся на сайте WikiSort.ru .




Текст в блоке "Читать" взят с сайта "Википедия" и доступен по лицензии Creative Commons Attribution-ShareAlike; в отдельных случаях могут действовать дополнительные условия.

Другой контент может иметь иную лицензию. Перед использованием материалов сайта WikiSort.ru внимательно изучите правила лицензирования конкретных элементов наполнения сайта.

2019-2024
WikiSort.ru - проект по пересортировке и дополнению контента Википедии