Язык программирования Си++ (1119468), страница 15
Текст из файла (страница 15)
p теряет значениеsort (v.begin (), v.end ());// Сортировка диапазонаfor (Cst i = 0; i < v.size (); i ++) {cout << v [i]; }}catch (out_of_range) { /* ... */ }// реакция на ошибочный индекс}int main () { Container v; f (v, 5, 12); }296Контейнер списков (list)#include <list>using namespace std;typedef list<int> Container;typedef Container::size_type Cst;void f (Container& v, int i1, int i2) {try { for (Cst i = 0; i < 10; i++) { v.push_back (i); } // Элементы: 0, 1, 2, ..., 9.// v.at (i1) = v.at (i2); Требуется перепрограммирование!cout << v.size ();// Размер контейнера для данной точкиContainer::iterator p = v.begin ();advance (p, 2);v.insert (p, 100); // Элементы: 0, 1, 100, 2, ..., 9.sort (v.begin (), v.end ());// Сортировка диапазонаfor (p = v.begin (); p != v.end (); ++ p) cout << * p;}catch (out_of_range) { /* ...
*/ }// реакция на ошибочный индекс}int main () { Container v; f (v, 5, 12); }297Достоинства STL-подхода• Все контейнеры обеспечивают стандартный интерфейс ввиде набора операций, один контейнер можетиспользоваться вместо другого, это не влечёт серьёзногоизменения текста программы• Дополнительная общность использования обеспечиваетсячерез стандартные итераторы• Каждый контейнер связан с распределителем памяти,который можно переопределить с тем, чтобы реализоватьсобственный механизм распределения памяти• Для каждого контейнера можно определитьдополнительные итераторы и интерфейсы, что позволитоптимальным образом настроить его для решения298конкретной задачиДостоинства STL-подхода• Контейнеры по определению однородны, то есть должнысодержать элементы одного типа, но возможно созданиеразнородных контейнеров как контейнеров указателей наобщий базовый класс• Алгоритмы, входящие в состав STL, предназначены дляработы с содержимым контейнеров, все алгоритмыпредставляют собой шаблонные функции, следовательно,их можно использовать для работы с любым контейнером299Недостатки STL-подхода• Не являясь производными от некоторого базового класса,контейнеры не имеют фиксированного стандартногопредставления (это же верно и для итераторов),использование стандартных контейнеров и итераторов неподразумевает никакой явной или неявной проверкитипов во время выполнения• Каждый доступ к итератору приводит к вызовувиртуальной функции, затраты по сравнению с вызовомобычной функции могут быть значительными• Предотвращение выхода за пределы контейнеравозлагается на программиста, при этом специальныхсредств контроля не предлагается300Новости стандарта Си++• Полностью разрешено использование типаlong long int• Введены типизированные перечисленияenum class E { V1, V2, V3 = 100, V4 /*101*/ };if (E::V4 == 101) … /* Ошибка! */• Тип констант не обязательно должен быть intenum class E { V1, V2, V3 = 100, V4 /*101*/ };if (E::V4 == 101) … /* Ошибка! */• Тип констант перечисления можно задать явно:enum class E2 : unsigned int { V1, V2 };Здесь значение Е2::V1 определено, а V1 – нет301Новости стандарта Си++• Для перечисления, заданного не строго:enum E3 : unsigned long { V1 = 1, V2 };определены оба значения: и Е3::V1, и значение V1• Возможно предварительное объявлениеперечислений, но только с указанием размера:enum E1; // Ошибка: низлежащий тип не определёнenum E2 : unsigned int;// OK!enum class E3; // OK: низлежащий тип intenum class E4 : unsigned long; // ОК!enum E2 : unsigned short;// Ошибка: Е2 ранее объявлен с другим типом 302Новости стандарта Си++• Имя NULL в языке Си++ определяется как константа созначением 0• Перегрузка функций может приводить к неверномувыбору функции f () при вызове вида f (NULL):int f (char * p); int f (int i);i = f (NULL); // int• В новом стандарте введено новое ключевое словоnullptr для значения пустого указателя типаstd::nullptr_t:char * pc = nullptr;int * pi = nullptr; // OK!bool b = nullptr; // OK: b == falseinti = nullptr; // Ошибка!i = f (0); /* int */i = f (nullptr); // char303 *Новости стандарта Си++• Новым стандартом расширены возможностиконтейнеров, в частности, разрешена ихинициализация, подобная инициализациивстроенных массивов:a [] = { 1, 2, 3, 4 };vector<int> v [] = { 1, 2, 3, 4 };• Для упорядоченных контейнеров введены методы,гарантированно дающие значения константныхитераторов:const_iterator cbegin ();const_iterator cend (); 304Новости стандарта Си++• Новым стандартом введено ключевое словоconstexpr:constexpr int give5 () { return 5; }int mas [give5 () + 7];// массив из 12 элементов• Ограничения:• функция не может быть типа void• тело функции должно иметь вид return выражение• выражение может вызывать только те функции, что такжеобозначены ключевым словом constexpr, или простоиспользовать обычные константы• функция, обозначенная с помощью constexpr,не может вызываться до её определения305Новости стандарта Си++• В константных выражениях можно использоватьпеременные любых числовых типовconstexpr double a = 9.8;constexpr double b = a/6;• Операцию определения размера объекта разрешеноприменять к членам-данным классов независимо отсамих объектов классовstruct A { some_type a; }; /* ...
*/sizeof (A::a) ... // OK!306Новости стандарта Си++• В старом стандарте требование указывать тип объекта внекоторых языковых конструкциях сильно их усложняло:for (vector<double, My_alloc<double> >::const_iteratorp = v.begin (); p != v.end (); ++ p)cout << *p << endl;• Новый стандарт допускает автоматическое выведение типаобъекта из типа инициирующего значения, что более экономнос точки зрения текста программы и более устойчиво кошибкам:for (auto p = v.cbegin (); p != v.cend (); ++ p)cout << *p << endl;307Новости стандарта Си++• Если ft () – функция, возвращающая значениенекоторого типа, переменная var1 будет иметьсоответствующий типauto var1 = ft ( /* ... */ );• Возможно также:auto var2 = 5; // var2 имеет тип int• Допускаются также определения:int v1;decltype (v1) v2 = 5;308Новости стандарта Си++• Пересчётный цикл по коллекции для встроенныхмассивов и коллекций с функциями begin () и end (),возвращающими итераторы:int arr[5] = {1, 2, 3, 4, 5};for (int &x : arr) { x *= 2; }• Делегирующие конструкторы:class A { int n;};public:A (int x) : n (x) {}A () : A (14) {}• Инициализация членов-данных класса в области ихобъявления в классе:class A { int n = 14; public: explicit A (int x) : n (x) {}A ( ) {}};309Новости стандарта Си++struct B { virtual void some_func ();virtual void f (int);virtual void g ()const;};struct D1 : public B {virtual void sone_func ()virtual void f (int)virtual void f (long)virtual void f (int)constvirtual int f (int)virtual void g ()constvirtual void g (long);};struct D2 : D1 { virtual void g ()const;};struct F final { int x,y; };struct G : F {int z;};override;override;override;override;override;final;// Ошибка: нет такой функции в В// OK!// Ошибка: несоответствие типа// Ошибка: несоответствие// Ошибка: несоответствие типа// OK!// OK: новая виртуальная функция// Ошибка: g () - финальная функция// Ошибка: наследование от финального класса310Новости стандарта Си++class Str { char * s;int len;public:Str (const char * sss = NULL); // традиционный конструктор неплоского классаStr (const Str &);// традиционный конструктор копированияStr (Str && x)// конструктор переноса из временного объекта{ s = x.s;x.s = NULL; // !!!len = x.len;}Str & operator = (const Str & x); // традиционная перегруженная операция =Str & operator = (Str && x)// быстрый перенос временного объекта{ s = x.s;x.s = NULL; // !!!len = x.len;return *this;}};~Str ();Str operator + (Str x);// традиционный деструктор неплоского класса// ...311.