Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

struct ltstr // функтор для сравнения объектов

Поиск

{

bool operator()(const char * s1, const char * s2) const

{

return strcmp(s1, s2) < 0;

}

};

int main() {

const int N = 6;

const char * a[N] = {"aaa", "bbb", "ccc", "ddd", "eee", "fff"};

const char * b[N] = {"zzzz", "eee", "ddd", "tt", "ff", "uuu"};

// формируем наборы из массивов

set<const char *, ltstr> A(a, a + N);

set<const char *, ltstr> B(b, b + N);

// создаем пустой контейнер для результата

set<const char *, ltstr> C;

cout << "Набор A: ";

copy(A.begin(), A.end(), ostream_iterator<const char *>(cout, " "));

cout << endl;

cout << "Набор B: ";

copy(B.begin(), B.end(), ostream_iterator<const char *>(cout, " "));

cout << endl;

cout << "Объединение: ";

set_union(A.begin(), A.end(), B.begin(), B.end(),

ostream_iterator<const char *>(cout, " "), ltstr());

cout << endl;

cout << "Пересечение: ";

set_intersection(A.begin(), A.end(), B.begin(), B.end(),

ostream_iterator<const char *>(cout, " "), ltstr());

cout << endl;

set_difference(A.begin(), A.end(), B.begin(), B.end(),

inserter[45](C, C.begin()), ltstr());

cout << "Набор C (разность A и B): ";

copy(C.begin(), C.end(), ostream_iterator<const char *>(cout, " "));

cout << endl;

return 0;

}

Важной особенностью контейнеров set и multiset является то, что вставка и удаление для них не нарушают корректность итераторов на другие элементы. Кроме того, из-за особого внутреннего представления контейнеров эти операции выполняются весьма быстро.

Шаблоны map и multimap содержат набор пар, в каждую из которых входят ключ и ассоциированный с ним объект. Параметризуются они четырьмя элементами: типом ключа, типом объекта, функтором сравнения (по умолчанию less<T>) и аллокатором. Примеры определения набора и мультинабора представлены ниже.

Примеры

map < int, MyClass, less<int> > MyClassMap;

multimap < int, MyClass, less<int> > MyClassMultiMap;

Базовые операции для map и multimap соответствуют операциям для set и multiset. Дополнительно шаблон map вводит операцию operator[], которая позволяет по ключу получить ассоциированный с ним объект. Шаблон multimap не вводит каких-либо новых операций.

Ниже приведен пример применения шаблона multimap.

Struct ltstr // функтор для сравнения ключей

{

bool operator()(const char * s1, const char * s2) const

{

return strcmp(s1, s2) < 0;

}

};

int main() {

multimap<const char *, int, ltstr> m;

// вставка пар в мультиотображение

m.insert(pair<const char * const, int>("a", 1));

m.insert(pair<const char * const, int>("c", 2));

m.insert(pair<const char * const, int>("b", 3));

m.insert(pair<const char * const, int>("b", 4));

m.insert(pair<const char * const, int>("a", 5));

m.insert(pair<const char * const, int>("b", 6));

// выделение объектов с одинаковыми ключами

cout << "Число объектов с ключом a: " << m.count("a") << endl;

cout << "Число объектов с ключом b: " << m.count("b") << endl;

cout << "Число объектов с ключом c: " << m.count("c") << endl;

// вывод всех объектов

cout << "Элементы m: " << endl;

for (multimap<const char *, int, ltstr>::iterator it = m.begin();

it!= m.end(); ++it)

cout << " [" << (*it).first << ", "

<< (*it).second << "]" << endl;

}

В примере для представления вставляемых компонент использован шаблон pair, который инкапсулирует свойства упорядоченных пар разнотипных объектов. Определяется шаблон pair в заголовочном файле pair.h. Для удобства вместо явного вызова конструктора пар можно было бы использовать функцию make_pair, определенную в файле utility.h.


Адаптеры

Адаптеры в STL служат для расширения возможностей существующих шаблонов. Такое расширение достигается введением новых компонент либо сокрытием существующих компонент. В STL выделяются три категории адаптеров: 1) адаптеры контейнеров; 2) адаптеры итераторов; 3) адаптеры функций.

Адаптеры контейнеров позволяют строить на основе существующих контейнеров контейнеры с новой функциональностью. К их числу относятся стеки, очереди и приоритетные очереди (все они будут доступны при условии включения заголовочного файла stack.h). Стек может быть получен из вектора, списка или двухсторонней очереди. Стек доопределяет пять новых компонентных функций: empty (проверка пустоты), size (текущий размер стека), top (значение объекта из вершины стека), push (запись элемента в вершину), pop (удаление объекта из вершины). Дополнительно вводятся операции для сравнения стеков operator== и operator<.

Пример

...

stack < vector<int> > s1; // стек на базе вектора

stack < list<int> > s2; // стек на базе списка

stack < deque<int> > s3; // стек на базе очереди

s1.push(1);

s1.push(5);

cout << s1.top() << endl;

s1.pop();

cout << s1.size() << endl;

s1.empty()? cout << "стек пуст": cout << "стек еще не пуст";

...

Очередь можно получить либо из списка, либо из двухсторонней очереди:

queue < list<int> > q1;

queue < deque<int> > q2;

Очередь доопределяет почти те же новые функции и операции, что и стек, только вместо функции top вводятся функции back (последний объект очереди) и front (первый объект очереди).

Приоритетную очередь получают от вектора или двухсторонней очереди. В приоритетной очереди, в отличие от обычной, объекты сортируются с помощью функтора comp, передаваемого через параметр. Приоритетная очередь инкапсулирует функции empty и size, push (запись объекта в очередь согласно его приоритету), pop (удаление объекта с максимальным приоритетом), top (получение наиболее приоритетного объекта).

Пример

...

// используем less как функтор сравнения

priority_queue < vector<int>, less<int> > pq1;

// используем greater как функтор сравнения

priority_queue < deque<int>, greater<int> > pq2;

vector v(3,1);

// создаем приоритетную очередь из вектора с функтором сравнения less

priority_queue < deque<int>, less<int> > pq3 (v.begin(), v.end());

...

Адаптеры итераторов предназначены для расширения функциональных возможностей итераторов. Выделяются два основных вида адаптеров итераторов: реверсивные итераторы и итераторы вставки. Реверсивные итераторы реализуют возможность прохождения контейнеров в обратном порядке (контейнер, по сути, рассматривается в направлении с хвоста к голове).

Многие контейнеры содержат компонентные функции rbegin, rend, которые подобно begin, end возвращают итераторы на начало и за конец контейнера; однако итератор на начало, возвращаемый rbegin, фактически ссылается на хвост контейнера, а для rend соответствующий итератор указывает перед началом контейнера. Например

list<int> l;

// записать в список значения 1 2 3 4

...

// вывод списка в обратном порядке

copy (l.rbegin(), l.rend(), ostream_iterator<int> (cout, " "));

В файле iterator.h явно определены шаблоны для введения реверсивных итераторов. Шаблон reverse_bidirectional_iterator позволяет определять двунаправленные реверсивные итераторы, а шаблон reverse_iterator – реверсивные итераторы произвольного доступа.

Еще пример:

list<int> l;

// заполнить список значениями 1 2 3 4

...

// вывод списка в обратном порядке

copy (reverse_iterator<int *, int, int &, ptrdiff_t>(l.end()),

reverse_iterator<int *, int, int &, ptrdiff_t>(l.begin()),

ostream_iterator<int> (cout, " ")); // выведет 4 3 2 1

В примере reverse_iterator<int *, int, int &, ptrdiff_t>() представляет собой вызов конструктора копирования итератора, который создает реверсивный итератор произвольного доступа по итератору, переданному через параметр.

Итераторы вставки служат для упрощения процедуры вставки объектов в контейнеры. Принцип их применения состоит в том, что вставляемый объект записывается в итератор, а последний обеспечивает его вставку в нужную позицию контейнера. В зависимости от этой позиции выделяются три вида итераторов вставки: back_insert_iterator (вставка в хвост); front_insert_iterator (вставка в голову); insert_iterator (вставка в произвольную позицию). Для использования итераторов первого вида контейнер должен поддерживать функцию вставки в конец (push_back); для итераторов второго вида необходима поддержка операции вставки в начало (push_front). Итераторы вставки обладают возможностями выходных итераторов.

Примеры формирования итераторов вставки:

deque<int> d;

back_insert_iterator < deque<int> > bi(d);

front_insert_iterator < deque<int> > fi(d);

insert_iterator < deque<int> > i (d, d.end());

Формирование итераторов вставки может быть автоматическим. Для этого предусмотрены шаблоны функций back_inserter, front_inserter, inserter (этот шаблон мы уже использовали выше). Их определения выглядят так:

template <class Container>

back_insert_iterator<Container> back_inserter(Container & x) {

return back_insert_iterator<Container>(x);

}

template <class Container>

front_insert_iterator<Container> front_inserter(Container & x) {

return front_insert_iterator<Container>(x);

}

template <class Container, class Iterator>

insert_iterator<Container> inserter(Container & x, Iterator i) {

return insert_iterator<Container>(x, Container::iterator(i));

}

Пример

ifstream f("example"); // содержимое файла example: 1 3

deque<int> d;

copy(istream_iterator<int, ptrdiff_t>(f),

istream_iterator<int, ptrdiff_t>(),

back_inserter(d)); // берем 1 3 из файла в d

vector<int> w (2,7); // вектор 7 7

copy(w.begin(), w.end(), front_inserter(d)); // вставляем w в начало d

insert_iterator < deque<int> > i = inserter(d, ++d.begin());

*i = 9; // вставляем 9 в d перед позицией итератора i

// результат 7 9 7 1 3

Кроме двух рассмотренных видов адаптеров итераторов, в STL имеется еще один адаптер, называемый итератором неинициализированной памяти (raw storage iterator). Этот итератор используется главным образом внутренними алгоритмами STL для разбиения и слияния контейнеров.

Адаптеры функций нацелены на расширение возможностей функций и функторов (определения их содержатся в файле function.h). Основные их категории: инверторы, байндеры, адаптеры указателей на функции. Инверторы (negator) служат для инвертирования значений предикатов:

template <class Predicate> // для унарных предикатов

unary_negate<Predicate> not1(const Predicate & pred) {

return unary_negate<Predicate>(pred);

}

template <class Predicate> // для бинарных предикатов

binary_negate<Predicate> not2(const Predicate & pred) {

return binary_negate<Predicate>(pred);

}

Пример

vector<int> v;

// записать в вектор числа 1 2 3 4

...

// сортировать по неубыванию

sort (v.begin(), v.end(), not2(less_equal<int>()));

Байндеры – это специальный вид функторов, которые связывают другие функторы со значениями. Например, требуется построить функтор «меньше 3» или «больше 7»; эту задачу можно решить байндером. Ниже приведен пример использования байндера. В примере в контейнере все значения меньшие некоторой границы заменяются этой границей.

vector<int> v;

// записать в вектор числа 4 6 10 3 13 2

...

int bound = 5; // граница

replace_if(v.begin(), v.end(), bind2nd(less<int>(), bound), bound);

// результат: v == 5 6 10 5 13 5

Байндер bind2nd возвращает новый функтор, требующий только один параметр, поскольку второй был связан с границей bound. При применении полученного функтора к разыменованному итератору i происходит сравнение *i < bound.

Стандартных байндеров в STL всего два: bind1st и bind2nd. Их определения представлены ниже.

template <class Operation, class T>

binder1st<Operation> bind1st(const Operation & op, const T & x)

{

return binder1st<Operation>(op, Operation::first_argument_type(x));

}

template <class Operation, class T>

binder2nd<Operation> bind2nd(const Operation & op, const T & x)

{

return binder2nd<Operation>(op, Operation::second_argument_type(x));

}

Здесь binder1st и binder2nd – это шаблоны классов, которые по существу и выполняют привязку функтора к значению.

Адаптер указателей на функции необходим для преобразования обычного функционального вызова в обращение к соответствующему функтору. Этот адаптер задается шаблоном ptr_fun и принимает в качестве аргумента любую унарную или бинарную функцию, возвращая соответствующий ей функтор. Полученный функтор осуществляет просто вызов функции, из которой он был получен. Ниже дан пример, в котором выполняется лексикографическая сортировка массива строк. Сортировка реализована алгоритмом sort, при этом лексикографический порядок задается стандартной функцией strcmp, преобразованной в функтор.

vector<char*> v;

char * c1 = new char[10]; strcpy (c1, "baa");

char * c2 = new char[10]; strcpy (c2, "abc");

char * c3 = new char[10]; strcpy (c3, "aad");

v.push_back(c1);

v.push_back(c2);

v.push_back(c3);

sort (v.begin(), v.end(), ptr_fun(strcmp));

copy (v.begin(), v.end(), ostream_iterator<char*> (cout, " "));

...

delete[] c1;

delete[] c2;

delete[] c3;

// результат: aad abc baa


Аллокаторы

Аллокаторы являются средством, позволяющим автоматизировать управление памятью в системах с различными моделями памяти и сделать приложения более переносимыми. Аллокаторы представляются в виде шаблонов, инкапсулирующих информацию о видах указателей, типе разности между ними, размере объектов, примитивах для работы с неинициализированной памятью и т.д. Аллокаторы параметризуют шаблоны контейнеров STL и все задачи, связанные с распределением памяти в этих контейнерах, решаются аллокаторами. Контейнер, просто говоря, ничего «не знает» об особенностях модели памяти, в которой он используется.

Как правило, параметры-аллокаторы имеют значения по умолчанию (см. выше) и их явное указание избыточно. Тем самым от пользователя скрывается семантика управления памятью в контейнерах. При необходимости, однако, указание особых аллокаторов в параметрах шаблонов возможно. В следующем небольшом примере создается список в условиях дальней модели памяти:

#include <faralloc.h> // для far_allocator

#include <list.h>

...

list <int, far_allocator> fl;

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

 


Вопросы для самопроверки

 

1. Охарактеризуйте назначение и организацию STL.

2. Какие компоненты входят в состав STL?

3. Определите понятия контейнера, алгоритма и итератора.

4. Охарактеризуйте виды контейнеров.

5. Перечислите шаблоны последовательных контейнеров в STL.

6. Чем отличаются друг от друга векторы, списки и двухсторонние очереди?

7. Каково назначение компонентных функций контейнеров begin и end?

8. Покажите на примере формирование объектов-векторов, объектов-списков и объектов-очередей.

9. Каким образом можно вставить элемент в вектор, список и очередь? Приведите фрагмент кода.

10. Покажите, как можно вставить в вектор группу смежных элементов из массива.

11. Приведите фрагмент кода, который осуществляет вывод элементов списка в поток cout.

12. Напишите фрагмент программы для соединения двух списков в один.

13. Какие категории итераторов имеются в STL? Перечислите их в порядке возрастания функциональных возможностей.

14. Какие операции свойственны входным итераторам и выходным итераторам?

15. Покажите на примере использование итераторов istream_iterator и ostream_iterator.

16. Какие новые возможности (операции) отличают однонаправленные и двунаправленные итераторы?

17. Назовите ограничения при работе с входными и выходными итераторами.

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

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

20. Дайте классификацию алгоритмов STL.

21. Назовите основные немодифицирующие алгоритмы.

22. Приведите пример линейного поиска значения в списке алгоритмом find_linear.

23. Каково назначение алгоритма adjacent_find?

24. Покажите на примере использование алгоритма find_if для поиска элемента в двухсторонней очереди.

25. Запишите фрагмент кода для вывода элементов списка в поток cout алгоритмом copy.

26. Какие алгоритмы сортировки применяются в STL?

27. Охарактеризуйте назначение алгоритмов transform, for_each и accumulate.

28. Приведите примеры применения алгоритмов из вопроса 27.

29. Запишите код для проверки четности суммы элементов вектора.

30. Какие стандартные функторы имеются в STL?

31. В чем состоит отличие ассоциативных контейнеров от последовательных?

32. Какие шаблоны ассоциативных контейнеров имеются в STL? Охарактеризуйте каждый из них.

33. Назовите основные операции, свойственные ассоциативным контейнерам.

34. Покажите на примере, как создать набор set из строк класса string.

35. Приведите пример создания отображения map и поиска в нем объекта.

36. Что понимается под адаптерами?

37. Какие виды адаптеров введены в STL?

38. Покажите на примере использование адаптера stack.

39. Что понимается под реверсивным итератором?

40. Каково назначение итераторов вставки? Приведите пример их использования.

41. Какую задачу решают байндеры bind1st и bind2nd?

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

43. Охарактеризуйте назначение аллокаторов.

 

Задачи

 

1. Решите задачу 1 из раздела 5, используя в качестве «внутреннего» контейнера множества какой-либо из стандартных контейнеров STL.

2. Переработайте шаблон задачи 2 из раздела 5 в соответствии с принципами организации контейнеров STL. Покажите совместную работу этого шаблона со стандартными алгоритмами, например find и replace.


заключение

Материал данного учебного пособия может существенно помочь в освоении языка С++, однако, лишь при условии интенсивной самостоятельной работы на ЭВМ непосредственно с компиляторами С++, исследовании системы помощи (Help), а также доступных для чтения заголовочных и исходных файлов. Существенную помощь способно оказать общение со специалистами в области программирования на С++ в рамках электронных конференций, имеющихся в сетях Интернет и ФИДО, изучение исходных текстов программ, размещенных на сайтах в сети Интернет. Тем, кто заинтересован в профессиональном овладении языком С++, целесообразна непосредственная работа с его стандартом [8].

 


Библиографический Список

 

1. Буч Г. Объектно-ориентированное проектирование с примерами применения: Пер. с англ. – М.: «Конкорд», 1992.

2. Страуструп Б. Язык программирования С++. –?

3. Скляров В.А. Язык С++ и объектно-ориентированное программирование: Справочное пособие. – Минск: Выш. школа, 1997.

4. Крячков А.В., Сухинина И.В., Томшин В.К. Программирование на С и С++: Практикум. – М.: «Горячая линия – Телеком», 2000.

5. Мейерс С. Эффективное использование С++. – М.: ДМК, 2000.

6. Мейерс С. Наиболее эффективное использование С++. – М.: ДМК, 2000.

7. Страуструп Б. Дизайн и эволюция языка С++. – М.: ДМК, 2000.

8. Programming Languages – C++. International Standard. – ISO/IEC 14882, 1998.


 

Зотов Игорь Валерьевич

Ширабакина Тамара Александровна

 

РАЗРАБОТКА ПРОГРАММ НА С++
ТЕОРИЯ, ПРИМЕРЫ РЕШЕНИЯ ЗАДАЧ,
ЭФФЕКТИВНОСТЬ

Учебное пособие

 

 

Редактор Н.В. Комардина

Компьютерная верстка и макет А.А. Гончаровой

 

6VPJ7-H3CXH-HBTPT-X4T74-3YVY7

Позиция плана № 18. 2003

ИД № 06430 от 10.12.01.

Подписано в печать. Формат 60х84 1/16. Печать офсетная.

Усл.печ.л..Уч.-изд.л. Тираж 200 экз. Заказ.

Курский государственный технический университет.

Издательско-полиграфический центр Курского государственного
технического университета. 305040, Курск, ул. 50 лет Октября, 94.


[1] Несмотря на свое название (constructor буквально переводится как «создатель») конструктор на самом деле не создает объект, а лишь инициализирует уже выделенный для объекта участок памяти определенными значениями (определяет начальное состояние объекта). Код для выделения памяти под объект формируется компилятором неявно.

[2] В отечественной (особенно переводной) литературе часто вместо «операция delete» пишут «оператор delete» (это относится и ко многим другим операциям), что совершенно некорректно. Причина некорректности – неточность перевода термина operator. Слово operator означает «операция», но никак не «оператор». Оператор же записывают как statement.

[3] Деструктор аналогично конструктору не уничтожает объект (хотя destructor означает «разрушитель»), а лишь выполняет завершающие действия перед фактическим уничтожением объекта.

[4] Термин «связь» использован для того, чтобы подчеркнуть различие между значением обычного указателя на объект (его значение есть адрес объекта) и указателем на компонент класса (его значением является по сути адрес компонента класса).

[5] Сказанное относится только к нестатическим компонентным функциям. У статических функций никаких модификаторов вводить нельзя, поскольку они не связаны с объектами.

[6] В других объектно-ориентированных языках вместо терминов «базовый» и «производный» часто используют другие. Например, в Object Pascal – соответственно «родительский» и «дочерний», в Java – соответственно «суперкласс» и «подкласс».

[7] Для производного класса допускаются только ключи struct и class.

[8] Класс CCenteredShape представляет абстрактное понятие и от него по смыслу нельзя создавать объекты, поэтому его лучше было бы определить как абстрактный класс (см. далее).

[9] Подробная информация о виртуальных деструкторах будет дана ниже. Здесь лишь отметим, что всякий базовый класс (или класс, который предполагается использовать как базовый) должен иметь виртуальный деструктор.

[10] Принято считать, что если класс содержит виртуальный деструктор, то он предназначен для использования в качестве базового класса. И обратно, если класс предполагается использовать как базовый, то в нем должен быть виртуальный деструктор.

[11] Естественно, для класса SomeBaseClass должна быть определена функция-операция operator <<, иначе вывод объектов в поток будет невозможным.

[12] COM = Component Object Model (модель компонентного объекта).

[13] ATL = Active Template Library (библиотека активных шаблонов). ATL служит для упрощения написания приложений в рамках технологии COM.

[14] При отсутствии реализации чисто виртуального деструктора возникает ошибка компоновки.

[15] Сказанное справедливо только при невиртуальном базовом классе. Если же базовый класс виртуальный, то его объект будет включаться в объект производного класса только один раз.

[16] Ничего не улучшит и использование макроса, если мы решим генерировать текст определения классов с его помощью, так как на вход компилятора все равно будет поступать множество практически одинаковых классов и компилятор будет создавать отдельный код для каждого класса.

[17] Процесс получения определения класса по шаблону принято называть инстанцированием.

[18] В библиотеке STL языка С++ имеется стандартный шаблонный класс векторов vector, поэтому наш класс в какой-то мере представляет собой попытку «изобретения велосипеда». Тем не менее для пояснения он весьма полезен.

[19] В стандарте языка С++ он именуется template_id.

[20] Легко заметить сходство между механизмами параметров функций и шаблонов. Однако есть и существенное отличие: у функций механизм параметров используется уже при выполнении программы, а у шаблонов – в процессе ее компиляции (при инстанцировании).

[21] По стандарту С++ эти параметры именуются non-type parameters (буквально «параметры-не-типы»). Но поскольку тяжело найти благозвучный перевод для non-type parameters, мы осмелимся далее использовать термин «ординарные» параметры.

[22] Согласно стандарту они называются integral promotions.

[23] Здесь речь идет о полной специализации. Есть также частичная специализация, речь о ней пойдет далее.

[24] Следует отметить, что перегрузка операций не имеет жесткой привязки к объектному подходу и может быть реализована даже в процедурных языках программирования. Однако она прекрасно «вписывается» в объектный подход и эффективно реализуется на его основе.

[25] Под @, естественно, подразумевается какой-либо знак стандартной операции, например + или *.

[26] При определенных условиях возможен даже переменный список параметров.

[27] Правила определения функций-операций более подробно будут обсуждаться в дальнейшем.

[28] Все, что мы говорим об операции ++, в равной мере относится и к операции ––.

[29] Значение 0 подставляется компилятором автоматически.

[30] Префиксную форму operator++ (operator––) легко реализовать на базе operator+=. Таким образом, достаточно поддерживать операцию +=.

[31] Напомним, что перегружать операции xxxx_cast (преобразование типов в стиле С++) запрещено.

[32] Правда, она возвращает указатель char *, а не const char *, что не вполне логично.

[33] Следует отметить, что аналогичная проблема возникает и с конструкторами копирования в иерархиях классов.

[34] Функторы являются частью стандартной библиотеки шаблонов (STL) С++ и подробно обсуждаются далее; здесь же основное внимание уделяется особенностям перегрузки операции operator().

[35] Объект является первым операндом для operator(), а список аргументов – вторым.

[36] В общем случае object_id – это выражение, результатом которого является объект класса, перегружающего операцию функционального вызова.

[37] Для встроенных типов операции new и delete не работают с конструкторами и деструкторами, поскольку их нет, и только выделяют / освобождают память.

[38] Например, объединение множеств и добавление элемента в множество можно реализовать операцией +, а перемножение матриц – операцией *.

[39] Вызов деструкторов на самом деле производится только для полностью построенных объектов, при этом неважно, автономны ли они или вложены в другие объекты (в том числе и «недостроенные»).

[40] Спецификации исключений применимы как к глобальным функциям, так и к компонентным функциям классов и шаблонов, и даже к шаблонам компонентных функций.

[41] Буквально переводится как «не пойманное» исключение.

[42] Подсчет ссылок не является специфическим механизмом языка С++, однако широко применяется в коде, написанном на С++, в частности, стандартной библиотеке, и имеет свои особенности при реализации на этом языке.

[43] const_iterator – это особый вид итераторов, значение которых обладает модификатором const.

[44] Есть также специальные итераторы потоков istream_iterator и ostream_iterator, упрощающие взаимодействие компонент STL с потоками (по своим возможностям они относятся к категориям входных и выходных итераторов соответственно).

[45] inserter – специальный шаблон функций, формирующий адаптер итератора insert_iterator, называемый итератором вставки.



Поделиться:


Последнее изменение этой страницы: 2016-08-14; просмотров: 153; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.191.171.10 (0.01 с.)