Важную роль в развитии языка C++ играют стандарты языка. Хотя язык C++ разрабатывался с 1980-х годов, первый стандарт языка C++98 был окончательно утвержден только в 1998 году.
В 2003 году был издан стандарт С++03, являющийся уточнением стандарта C++98.
Наиболее существенные изменения языка произошли в стандарте C++11, разработка которого завершилась в 2011 году. Далее будут изложен ряд нововведений стандарта C++11.
В 2014 году был издан стандарт С++14, не содержащий существенных изменений, а только устраняющий ряд дефектов стандарта С++11.
Разработка следующего стандарта C++17 будет завершена в 2017 году. Этот стандарт также содержит ряд интересных нововведений, однако их не столь много, как в стандарте С++11.
Статья в википедии про стандарт С++11
Таблица поддержки нововведений стандартов С++11, С++14, С++17 в разных компиляторах
mingw-w64-install.exe - установщик свежей версии компилятора mingw-w64 для Windows
При работе с контейнерами STL иногда приходится писать конструкции вида
map<int, pair<string, double>>::reverse_iterator it;
То есть описание типа может быть очень длинной строкой. Вместо этого в C++11 можно объявить имя типа, как auto, что означает, что компилятор должен сам определить тип переменной. В этом случае переменная должна быть явно инициализирована при объявлении, например:
auto it = a.begin();
В этом случае компилятор знает тип значения a, поэтому он может определить тип, который возвращает метод begin(), и тем самым будет определен тип переменной it.
Самый простой вариант (можно использовать для определения того, включена ли поддержка C++11):
auto a = 0;
В этом случае переменная a будет иметь тип int. Если написать:
auto a = 0.0;
то переменная a будет иметь тип double.
Обратите внимание, это НЕ динамическая типизация! Переменная по-прежнему имеет строго определенный тип, который не может быть впоследствии изменен! Но этот тип программист просто не указывает явно для облегчения труда.
В C++11 появились range-based циклы: циклы, в которых переменная пробегает по всем значением контейнера. Контейнер должен поддерживать методы begin() и end() -- это может быть vector, list, set, map.
Пример такого цикла для вывода элементов вектора:
vector<int> a;
for (int elem: a)
cout << elem << endl;
Очень часто в качестве типа переменной используется слово auto.
Таким образом можно модифицировать элементы вектора, если сделать цикл по переменной-ссылке, а не по переменной-значению:
vector<int> a;
for (auto & elem: a)
++elem;
Если цикл пробегает по элементам контейнера map, то переменная будет парой из двух элементов: ключ и значение. То есть:
map<int, int> a;
for (auto & elem: a)
{
// a.first - ключ элемента словаря, a.second - его значение
}
В языке C элементы массива можно инициализировать списком значений, например, так:
int a[3] = {1, 2, 3};
В С++11 такая универсальная инициализация распространена на структуры и классы. В списке инициализации в фигурных скобках необходимо указать значения полей структуры в том порядке, в котором они объявлены. Например,
struct point {
int x, y;
};
point P;
P = {1, 2};
В этом случае P.x будет равно 1, P.y будет 2.
Еще один способ использования универсальной инициализации:
point P{1, 2};
Поскольку pair является структурой, то этот способ можно использовать для инициализации pair. Например, если функция возвращает значение типа pair, то можно написать:
return {a, b};
вместо
return make_pair{a, b};
В C++11 появилась возможность создания шаблонов с переменным числом аргументов. Один из примеров такого шаблона - tuple, определенный в одноименном заголовочном файле. Это кортеж, то есть переменная, которая содержит несколько полей различных типов.
Например:
tuple<string, string, int> person;
Доступ к составным полям tuple осуществляется при помощи функции-шаблона get с одним числовым параметром -- номер поля, к которому производится доступ. Например:
get<0>(person) = "Peter";
get<1>(person) = "Ivanov";
get<2>(person) = 16;
Заметим, что инстанцирование шаблона происходит при компиляции, то есть порядковый номер поля должен быть константой, определенной на момент компиляции (нельзя сделать цикл по номеру поля, т.е. нельзя, например, написать
for (int i = 0; i < 3; ++i) {cout << get<i>(person) << " "};
Объекты класса tuple сравниваются в лексикографическом порядке, поэтому их удобно использовать при сортировке векторов вместо pair, если нужно сортировать по нескольким параметрам.
tie является структурой, определенной в заголовочном файле tuple. Структура tie похожа на tuple, только членами структуры являются ссылки на какие-либо переменные (или прочие lvalue, например, элементы массива и т.д.). Это позволяет модифицировать переменные, переданные в качестве параметров при создании tie.
Пример. Пусть функция f возвращает пару значений, то есть структуру pair или tuple. Хочется записать эти значения в две переменные. Раньше мы писали так:
auto res = f();
a = res.first;
b = res.second;
С использованием tie это можно сделать так:
tie(a, b) = f();
Лямбда-функции - это безымянные функции, которые не получают собственного имени, а используются только в месте объявления.
Распространенное использование лямбда-функций - это параметр-компаратор при сортировке. Вместо создания специальной функции-компаратора, можно описать функцию прямо в вызове функции sort.
Пример - отсортируем vector<int> a по последней цифре числа:
sort(a.begin(), a.end(), [](int x, int y) -> bool {return x % 10 < y % 10;});
В языке C для обозначения нулевого указателя использовался макрос NULL, который на самом деле был объявлен так:
#define NULL 0
То есть NULL является значением типа int, что может привести к проблемам сравнения указателя с целым числом. В стандарте C++11 для обозначения нулевого указателя появилось новое специальное значение nullptr.
При определении вложенных шаблонов, например:
vector <vector<int>> a;
в C++11 можно не ставить пробел между "<<", что было обязательным в ранних версиях C++.
С С++11 стандартизирован тип long long int, который раньше был расширением GNU C++.
Кроме того, появились типы данных фиксированного размера, например, "32-битное целое число", они определены в заголовочном файле cstdint.
Много изменений произошло в стандартной библиотеке. Например, появились хеш-таблицы unordered_set и unordered_map. Появились усовершенствованные генераторы случайных чисел и поддержка регулярных выражений.