МИВК Многофункциональный
информационно-вычислительный
комплекс ОИЯИ

EN

Новые возможности C++11

ROOT 6 написан на стандарте С++11. Для успешного использования этой версии ROOT следует ознакомиться с отличиями С++11 от предыдущих версий С++. Приведем здесь список наиболее значимых из них:

Изменения, затронувшие основу языка:

1

Определены новые зарезервированные ключевые слова: alignas, alignof, array, char16_t, char32_t, constexpr, decltype, index, noexcept, nullptr, static_assert, thread_local. Ниже каждое из этих слов рассматривается отдельно.

2

Добавлены новые типы данных: long long int,char16_t, char32_t.

3

Введено понятие rvalue ссылок (определенных с & &), чтобы отличать ссылку на lvalue (объект, у которого есть имя) и ссылку на rvalue (объект, у которого нет имени). Ссылки на временные значения ( rvalues значения на правой стороне присвоения) позволяют изменять такие значения после их инициализации. Класс/структура раньше имели некоторые неявные функции-члены: конструктор по умолчанию (если другой конструктор не определен), конструктор копирования и деструктор. Конструктор копирования выполняет поразрядное копирование переменных. Это означает, что если есть класс с указателями на какие-то объекты, то конструктор копирования скопирует указатели, а не объекты, на которые они указывают. Если необходимо получить в копии именно объекты, а не лишь указатели на них, то это нужно явно описать в конструкторе копирования. В С++11 добавлены конструктор переноса (перемещения) и оператор присваивания перемещения. Эти две специальные функции принимают параметр T& &, который является rvalue. Фактически, они могут изменять объект.

4

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

5

Изменилось определение типа простых данных (plain old data или POD). Простая структура данных имеет жёстко определённое расположение полей в памяти, не требующее ограничения доступа и автоматического управления. Переменные такого типа можно копировать простыми процедурами копирования участков памяти. В С++11 оно разбито на два: тривиальный тип (позволяющий статическую инициализацию и использование memcpy) и тип стандартного размещения (порядок его членов совместим с порядком C). Это позволяет более точно задавать границы совместимости типа с C.

6

Введено понятие внешнего шаблона - способа запретить компилятору инстанцировать (создавать экземпляр класса) шаблон.

7

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

struct Object

{

    float first;

    int second;

};

Object scalar = {0.43f, 10}; // один объект, с first=0.43f и second=10

Object anArray[] = {{13.4f, 3}, {43.28f, 29}, {5.934f, 17}}; // массив из трёх объектов

Списки инициализации очень полезны для статических списков и в тех случаях, когда требуется инициализировать структуру определённым значением. C++ также содержит конструкторы, которые могут содержать общую часть работы по инициализации объектов. Стандарт C++ позволяет использовать списки инициализации для структур и классов при условии, что те соответствуют определению простого типа данных (Plain Old Data POD). Классы, не являющиеся POD, не могут использовать для инициализации списки инициализации, в том числе это касается и стандартных контейнеров C++, таких, как векторы. C++11 связал концепцию списков инициализации и шаблонный класс, названный std::initializer_list. Это позволило конструкторам и другим функциям получать списки инициализации в качестве параметров. Например:

class SequenceClass

{

public:

  SequenceClass(std::initializer_list list);

};

Данное описание позволяет создать SequenceClass из последовательности целых чисел следующим образом:

SequenceClass someVar = {1, 4, 5, 6};

Класс std::initializer_list<> определён в стандартной библиотеке C++11. Однако, объекты данного класса могут быть созданы компилятором C++11 только статически с использованием синтаксиса со скобками {}. Список может быть скопирован после создания, однако, это будет копированием по ссылке. Список инициализации является константным: ни его члены, ни их данные не могут быть изменены после создания.

8

C++11 предоставляет синтаксис, позволяющий использовать единую форму инициализации для всех видов объектов с помощью расширения синтаксиса списков инициализации:

struct BasicStruct {

    int x;

    double y;

};

struct AltStruct {

    AltStruct(int x, double y) : x_(x), y_(y) {}

private:

    int x_;

    double y_;

};

BasicStruct var1{5, 3.2};

AltStruct var2{2, 4.3};

Универсальная инициализация не заменяет полностью синтаксиса инициализации с помощью конструктора. Если в классе есть конструктор, принимающий в качестве аргумента список инициализации (ИмяТипа(initializer_list);), он будет иметь более высокий приоритет по сравнению с другими возможностями создания объектов. Например, в C++11 std::vector содержит конструктор, принимающий в качестве аргумента список инициализации:

std::vector theVec{4};

Данный код приведёт к вызову конструктора, принимающего в качестве аргумента список инициализации, а не конструктор с одним параметром, создающий контейнер заданного размера. Для вызова этого конструктора необходимо использовать стандартный синтаксис вызова конструктора.

9

Добавлены возможности вывода типов: переменные, инициализирующиеся при объявлении, могут быть объявлены как auto, а ключевое слово decltype позволяет определять тип переменной на этапе компиляции. До С++11, ключевое слово auto использовалось как спецификатор хранения переменной (как, например, register, static, extern). В С++11 auto позволяет не указывать тип переменной явно, говоря компилятору, чтобы он сам определил фактический тип переменной, на основе типа инициализируемого значения. Это может использоваться при объявлении переменных в различных областях видимости, как, например, пространство имен, блоки, инициализация в цикле и т.п. auto i = 42; // i - int auto l = 42LL; // l - long long auto p = new foo(); // p - foo*

10

Добавлен синтаксис цикла типа foreach для итерирования по элементам коллекции. В новой форме возможно выполнять итерации в случае, если для объекта итерации перегружены методы begin() и end(). Это полезно, когда необходимо просто получить элементы массива/контейнера или сделать с ними что-то, не заботясь об индексах, итераторах или количествеве элементов.

11

Добавлена поддержка анонимных лямбда-функций.

12

Добавлен новый синтаксис объявления шаблонов функций, с указанием типа возвращаемого значения после перечисления аргументов функции.

13

Введены "интеллектуальные указатели" с подсчетом ссылок и автоматическим освобождением памяти: unique_ptr: должен использоваться, когда ресурс памяти не должен был разделяемым (у него нет конструктора копирования), но он может быть передан другому unique_ptr shared_ptr: должен использоваться, когда ресурс памяти должен быть разделяемым weak_ptr: содержит ссылку на объект, которым управляет shared_ptr, но не осуществляет подсчет ссылок; позволяет избавиться от циклической зависимости

14

Конструкторы класса могут вызывать другие конструкторы этого же класса, как в Java, C# и D. Объект считается созданным, как только отработал хотя бы один конструктор.

15

Добавлены два новых идентификатора: override, для указания того, что метод является переопределением виртуального метода в базовом классе и final, указывающий что производный класс не должен переопределять виртуальный метод.

16

Введено новое ключевое слово nullptr, определяющее нулевой указатель. Раньше, для обнуления указателей использовался макрос NULL, являющийся нулем целым типом, что, естественно, вызывало проблемы (например, при перегрузке функций). Ключевое слово nullptr имеет свой собственный тип std::nullptr_t, что избавляет от этих проблем. Существуют неявные преобразования nullptr к нулевому указателю любого типа и к bool (как false), но преобразования к целочисленных типам нет.

17

У «традиционных» перечислений в С++ есть некоторые недостатки: они экспортируют свои значения в окружающую область видимости (что может привести к конфликту имен), они неявно преобразовываются в целый тип и не могут иметь определенный пользователем тип. Эти проблемы устранены в С++11 с введением новой категории перечислений, названных strongly-typed enums. Они определяются ключевым словом enum class. Они больше не экспортируют свои перечисляемые значения в окружающую область видимости, больше не преобразуются неявно в целый тип и могут иметь определенный пользователем тип (эта опция так же добавлена и для «традиционных» перечислений).

enum class Options {None, One, All};

Options o = Options::All;

18

Изменение спецификации парсера так, что >> интерпретируется как пара закрывающих скобок, а не как оператор правого сдвига.

19

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

20

Синонимы шаблонов.

21

Убраны некоторые ограничения на то, объекты каких типов могут входить в union.

22

Разрешены шаблоны с переменным количеством параметров.

23

Поддержка трех новых типов строковых констант: UTF-8 (u8"..."), UTF-16 (u"...") и UTF-32 (U"..."). пользовательские константы (возможность трактовать запись как константу некоторого типа в зависимости от ее суффикса).

24

Многопоточная модель памяти.

25

Хранение данных, локальных для потока.

26

Добавлен static_assert, которвй проверяет утверждение во время компиляции. Если утверждение истина, то ничего не происходит. Если ложь, то компилятор выводит указанное сообщение об ошибке.

27

Sizeof может работать с членами классов без объектов этого класса.

28

Добавлена возможность управления размещением переменных.

29

Убраны некоторые сценарии, которые делали невозможным реализацию автоматической сборки мусора.

30

Введены функции begin() и end(). Это новое дополнение к стандартной библиотеке. Они работают со всеми контейнерами STL и могут быть расширены для работы с любым типом.

 

Изменения библиотеки STL:

1

Поддержка многопоточности (классы потоков, мьютексов, условных переменных, блокировок и т.д.).

2

Добавлен кортеж (std::tuple) - неоднородный список элементов. Кортеж "похож" на пару (std::pair), однако он может содержать произвольное (хотя и конечное) количество элементов. Создать кортеж можно так:

#include

std::tuple tuple_("hello", 42, 3.14);

Кортеж можно назвать коллекцией гетерогенных (разнородных) значений. Поэтому тип элемента (value_type), который определен в любом стандартном контейнере, не имеет смысла в кортеже, и просто отсутствует, ровно как и любой из типов итераторов. Кортеж не является обычным контейнерным классом, и не отвечает концепции контейнеров в С++. Поэтому простого способа обхода элементов кортежа нет. К нему не применимы какие-либо циклы:

for (auto& x : tuple_);  // Ошибка компиляции!

error: no viable 'begin' function available

"Пройтись" по элементам кортежа можно только точно зная количество его аргументов на этапе компиляции. Для этого нужно использовать функцию get:

std::get<0>(tuple_); // индекс элемента в качестве аргумента шаблона

std::get<1>(tuple_);

std::get<2>(tuple_);

При этом передача индекса во время выполнения программы невозможна:

int i = 0;

std::get< i >(tuple_);  // Ошибка компиляции!

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

3

Коллекции разнородных объектов заданных размерностей.

4

Хеш-таблицы (неупорядоченные ассоциативные контейнеры) unordered_set, unordered_multiset, unordered_map и unordered_multimap.

5

Библиотека регулярных выражений &< regex &>.

6

“Умные” указатели общего назначения: добавлен unique_ptr и улучшены shared_ptr​ и ​weak_ptr, auto_ptr исключен как устаревший.

7

Расширенные возможности генерации случайных чисел