Лекция-2.08.ppt
- Количество слайдов: 61
Стандартная библиотека языка С++ C++ standard library 1. Назначение стандартной библиотеки. 2. Состав и структура библиотеки. 3. Общая характеристика. 4. Контейнеры. 5. Итераторы. 6. Алгоритмы. 7. Строки. Лекция 3 -7. 04. 2014 г. 1
Назначение стандартной библиотеки Ни одна «серьезная» программа не может быть написана только с использованием «чистых» конструкций языка; программисты обязательно используют средства поддержки, которые, как правило, разрабатываются одновременно с языком, реализуются в виде библиотек поддержки и создают основу для успешной работы. Стандартная библиотека С++ является «надстройкой» над языком и существенно расширяет его базовые возможности, предоставляя разработчикам большое количество удобных и полезных конструкций, которые могут использоваться ими в качестве «строительных блоков» для своих программ. Описание библиотеки и требования к ней (состав, интерфейсы, функциональность и пр. ) включены в международный стандарт языка С++: Information technology - Programming languages – C++, INTERNATIONAL STANDARD ISO/IEC 14882, Third edition 2011 -09 -01, 786 p. Лекция 3 -7. 04. 2014 г. 2
Лекция 3 -7. 04. 2014 г. 3
1. Назначение стандартной библиотеки. 2. Состав и структура библиотеки. 3. Общая характеристика STL. 4. Контейнеры. 5. Итераторы. 6. Алгоритмы. 7. Строки. Лекция 3 -7. 04. 2014 г. 4
Состав и структура библиотеки Физически библиотека состоит из набора заголовков (заголовочных файлов), в каждом из которых объявляются макросы, значения (константы), типы, классы, функции и объекты, предназначенные для использования в программах. Большая часть библиотеки реализована с помощью шаблонов, поэтому обычно ее реализация почти целиком располагается в заголовочных файлах. Некоторые части библиотеки скомпилированы отдельно и должны быть скомпонованы с программой на С++. Детали этого процесса определяются реализацией. Лекция 3 -7. 04. 2014 г. 5
Состав библиотеки В стандарте вся библиотека разбита на 13 категорий (гл. 18 -30): 1)Language support library 2)Diagnostics library 3)General utilities library 4)Strings library 5)Localization library 6)Containers library 7)Iterators library 8)Algorithms library 9)Numerics library 10)Input/output library 11)Regular expressions library 12)Atomic operations library 13)Thread support library Лекция 3 -7. 04. 2014 г. 6
Лекция 3 -7. 04. 2014 г. 7
Библиотека MSDN (англ. MSDN Library) — библиотека официальной технической документации для разработчиков приложений под ОС Microsoft Windows. MSDN расшифровывается как Microsoft Developer Network. Библиотека MSDN содержит документацию на API продуктов Microsoft, а также код примеров, технические статьи и другую полезную для разработчиков информацию. Она бесплатно доступна через Интернет, а также на CD и DVD для подписчиков MSDN. Лекция 3 -7. 04. 2014 г. 8
msdn. microsoft. com/ru-ru/library/a 7 tkse 1 h(v=vs. 100). aspx Лекция 3 -7. 04. 2014 г. 9
http: //www. cplus. com/reference/ Лекция 3 -7. 04. 2014 г. 10
STL - Standard Template Library Библиотека стандартных шаблонов STL была первоначально разработана сотрудниками Hewlett-Packard А. Степановым и М. Ли совместно с Д. Муссером из Ренсселэровского политехнического института. После внесения незначительных поправок Комитет по стандартизации языка C++ принял STL, сделав ее существенной составной частью стандартной библиотеки языка С++. Использование STL дает возможность создавать более надежные, более переносимые и более универсальные программы, а также сократить расходы на их разработку Это значит, что любой профессиональный программист должен знать эту библиотеку. Концепция STL основана на разделении данных и операций. Данные находятся под управлением контейнерных классов, а операции определяются адаптируемыми алгоритмами. Итераторы выполняют функции «соединителя» , связывающего эти два компонента. Благодаря им любой алгоритм может работать с любым контейнером. Лекция 3 -7. 04. 2014 г. 11
1. Назначение стандартной библиотеки. 2. Состав и структура библиотеки. 3. Общая характеристика STL. 4. Контейнеры. 5. Итераторы. 6. Алгоритмы. 7. Строки. Лекция 3 -7. 04. 2014 г. 12
Контейнеры предназначены для управления коллекциями объектов определенного типа. У каждой разновидности контейнеров имеются свои достоинства и недостатки, поэтому существование разных контейнеров отражает различия между требованиями к коллекциям в программах. Контейнеры могут быть реализованы в виде массивов или связанных списков, а каждый элемент может снабжаться специальным ключом. Контейнеры делятся на 4 основных категории: 1. Последовательные контейнеры (5 типов) 2. Ассоциативные контейнеры (2 типа) 3. Неупорядоченные ассоциативные контейнеры (2 типа) 4. Контейнерные адаптеры (2 типа) Лекция 3 -7. 04. 2014 г. 13
Категории и типы контейнеров Лекция 3 -7. 04. 2014 г. 14
Sequence containers vector deque list forward_list array Лекция 3 -7. 04. 2014 г. 15
Последовательные контейнеры – это упорядоченные коллекции, в которых каждый элемент занимает определенную позицию. Позиция зависит от времени и места вставки, но не связана со значением элемента. Поддержка работы с последовательными контейнерами представлена в заголовочных файлах: vector – содержит определение шаблонного класса vector, его специализации vector<bool>, а также определение внешней шаблонной функции swap и перегруженных шаблонных операций: ==, !=, <, <=, >, >=; deque – содержит определение шаблонного класса deque (двунаправленная очередь, или дек), а также определение внешней шаблонной функции swap и перегруженных шаблонных операций: ==, !=, <, <=, >, >=; Лекция 3 -7. 04. 2014 г. 16
Последовательные контейнеры Sequence containers list - содержит определение шаблонного класса list (двунаправленный список), а также определение внешней шаблонной функции swap и перегруженных шаблонных операций: ==, !=, <, <=, >, >=; forward_list - содержит определение шаблонного класса forward_list (однонаправленный список), а также определение внешней шаблонной функции swap и перегруженных шаблонных операций: ==, !=, <, <=, >, >=; array - содержит определение шаблонного класса array (массив фиксированного размера), а также определение внешней шаблонной функции swap и перегруженных шаблонных операций: ==, !=, <, <=, >, >=. Лекция 3 -7. 04. 2014 г. 17
vector – последовательный контейнер, который поддерживает итераторы произвольного доступа. Кроме того, vector поддерживает операции вставки и удаления в конце последовательности с постоянным временем; вставка и удаление в середине занимают линейное время. int main () { vector<int> v 1; // Пустой вектор из целых чисел. cout << "empty = " << v 1. empty() << endl; cout << "size = " << v 1. size() << endl; cout << "max_size = " << v 1. max_size() << endl; v 1. push_back(42); // Добавление целого числа к вектору. cout << "size = " << v 1. size() << endl; cout << "v 1[0] = " << v 1[0] << endl; system("PAUSE"); return 0; } Лекция 3 -7. 04. 2014 г. 18
Примеры конструкторов шаблонного класса vector #include <vector> #include <iostream> using namespace std; void Print(string s, vector<int> v) { cout << s; for( vector<int>: : iterator i = v. begin( ) ; i != v. end( ) ; i++ ) cout << " " << *i; cout << endl; } int main( ) { vector<int>: : iterator i; vector<int> v 0; Print("v 0 = ", v 0); vector<int> v 1( 3 ); // Вектор из 3 -х нулевых элементов Print("v 1 = ", v 1); vector<int> v 2( 5, 2); // Вектор из 5 элементов, имеющих значение 2 Print("v 2 = ", v 2); int myints[] = {16, 2, 77, 29}; . . . Лекция 3 -7. 04. 2014 г. 19
Примеры конструкторов шаблонного класса vector. . . int myints[] = {16, 2, 77, 29}; vector<int> v 3(myints, myints + sizeof(myints) / sizeof(int) ); Print("v 3 = ", v 3); vector<int> v 4( v 2 ); // Копия вектора v 2 Print("v 4 = ", v 4); vector<int> v 5( 5 ); for( int index = 0; index < 5; index++ ) v 5[index] = index; Print("v 5 = ", v 5); vector<int> v 6( v 5. begin( ) + 1, v 5. begin( ) + 3 ); Print("v 6 = ", v 6); // Move vector v 2 to vector v 7 vector<int> v 7( move(v 2) ); Print("v 7 = ", v 7); Print("v 2 = ", v 2); v 2. push_back(100); Print("v 2 = ", v 2); v 2 = move(v 7); Print("v 7 = ", v 7); Print("v 2 = ", v 2); } Лекция 3 -7. 04. 2014 г. 20
Использование новых возможностей языка С++ В последней версии стандарта языка С++ появилось много новых возможностей, позволяющих упростить процесс программирования и сделать программы более надежными. Рассмотрим две из них: 1. Вывод типа объявляемой переменной из инициализатора: auto x = 7; //переменная x будет иметь тип int С использованием этой новой синтаксической конструкции текст программы с предыдущего слайда можно немного упростить: вместо такого цикла for( vector<int>: : iterator i = v. begin( ) ; i != v. end( ) ; i++ ) cout << " " << *i; можно записать более просто: for( auto i = v. begin( ) ; i != v. end( ) ; i++ ) cout << " " << *i; Лекция 3 -7. 04. 2014 г. 21
Использование новых возможностей языка С++ 2. Диапазонный оператор цикла for, который позволяет итерировать по «диапазону» , что позволяет «пройтись» по любой STL последовательности, заданной методами begin() и end(). Все стандартные контейнеры могут быть использованы в качестве «диапазона» . Так, предыдущий упрощенный оператор цикла можно записать еще более компактно: вместо for( auto i = v. begin( ) ; i != v. end( ) ; i++ ) cout << " " << *i; можно записать еще более просто: for( auto i : v ) cout << " " << i; Еще примеры диапазонного for: for( auto i : {23, 17, 35, 64} ) cout << " " << i; int m[] = {23, 17, 35, 64} ; for( auto i : m ) cout << " " << i; Лекция 3 -7. 04. 2014 г. 22
Еще примеры с vector. int main () { vector<int> v (4); v[0] = 1; v[1] = 4; v[2] = 9; v[3] = 16; cout << "front = " << v. front () << endl; cout << "back = " << v. back () << ", size = " << v. size () << endl; v. push_back (25); cout << "back = " << v. back () << ", size = " << v. size () << endl; v. pop_back (); cout << "back = " << v. back () << ", size = " << v. size () << endl; system("PAUSE"); return 0; } Лекция 3 -7. 04. 2014 г. 23
Еще примеры с vector. int array 1[] = { 1, 4, 25 }; int array 2[] = { 9, 16 }; int main () { vector<int> v (array 1, array 1 + 3); v. insert (v. begin (), 0); // Всавка перед первым элементом. v. insert (v. end (), 36); // Всавка последнего элемента. for (int i = 0; i < v. size (); i++) cout << "v[" << i << "] = " << v[i] << endl; cout << endl; // Вставка содержимого array 2 перед четвертым элементом. v. insert (v. begin () + 3, array 2 + 2); for (int i = 0; i < v. size (); i++) cout << "v[" << i << "] = " << v[i] << endl; cout << endl; system("PAUSE"); return 0; } Лекция 3 -7. 04. 2014 г. 24
Еще примеры с vector. #include <vector> #include <iostream> using namespace std; template <class T> void Print(string s, T v) { cout << s; for( auto i : v ) cout << " " << i; cout << endl; } int main( ) { vector <int> v 1; v 1. push_back( 10 ); v 1. push_back( 20 ); v 1. push_back( 30 ); Print("v 1 = ", v 1); v 1. insert( v 1. begin( ) + 1, 40 ); Print("v 1 = ", v 1); v 1. insert( v 1. begin( ) + 2, 4, 50 ); Print("v 1 = ", v 1); v 1. insert( v 1. begin( )+1, v 1. begin( )+2, v 1. begin( )+4 ); Print("v 1 = ", v 1); vector <int> > vv 1; vv 1. insert( vv 1. begin(), move( v 1 ) ); Print("vv 1[0] = ", vv 1[0]); } Лекция 3 -7. 04. 2014 г. 25
deque - вид последовательности, которая, подобно вектору, поддерживает итераторы произвольного доступа. Кроме того она поддерживает операции вставки и удаления в начале или в конце последовательности за постоянное время; вставка и удаление в середине занимают линейное время. int main () { deque<int> d; d. push_back (4); // Вставка в конце. d. push_back (9); d. push_back (16); d. push_front (1); // Вставка в начале. for (int i = 0; i < d. size (); i++) cout << "d[" << i << "] = " << d[i] << endl; cout << endl; d. pop_front (); // Удаление первого элемента. d[2] = 25; // Замена последнего элемента. for (int i = 0; i < d. size (); i++) cout << "d[" << i << "] = " << d[i] << endl; system("PAUSE"); return 0; } Лекция 3 -7. 04. 2014 г. 26
list - вид последовательности, которая поддерживает двунаправленные итераторы и допускает операции вставки и удаления с постоянным временем в любом месте последовательности. В отличие от векторов и двусторонних очередей, быстрый произвольный доступ к элементам списка не поддерживается, но в большинстве случаев бывает нужен только последовательный доступ. int array 1 [] = { 9, 16, 36 }; int array 2 [] = { 1, 4 }; int main () { list<int> l 1 (array 1, array 1 + 3); list<int> l 2 (array 2, array 2 + 2); list<int>: : iterator i 1 = l 1. begin (); l 1. splice (++i 1, l 2); list<int>: : iterator i 2 = l 1. begin (); while (i 2 != l 1. end ()) cout << *i 2++ << endl; system("PAUSE"); return 0; } Лекция 3 -7. 04. 2014 г. 27
array - это последовательный контейнер фиксированного размера с возможностью прямого доступа к элементам. У него нет дополнительного расхода памяти для хранения элементов, он может инициализироваться с помощью списка инициализации, знает свой размер (количество элементов), и не может быть неявным образом преобразован к указателю. Этот контейнер очень похож на стандартный массив, но без его недостатков. #include <iostream> #include <array> using namespace std; int main() { array<int, 3> myarray = {5, 19, 77}; cout << "front is: " << myarray. front() << std: : endl; // 5 cout << "back is: " << myarray. back() << std: : endl; // 77 myarray. back() = 50; for ( auto x : myarray ) cout << ' ' << x; cout << 'n'; for ( auto r = myarray. rbegin(); r < myarray. rend(); ++r) cout << ' ' << *r; cout << 'n'; return 0; } Лекция 3 -7. 04. 2014 г. 28
Замечания по поводу реализации (внутреннего устройства) последовательных контейнеров vector Контейнер реализован на базе обычного массива со специальной стратегией упреждающего выделения дополнительной памяти для возможного роста массива. В связи с этим добавление нового элемента в конец массива с помощью функции push_back почти всегда выполняется очень быстро. Также быстро происходит доступ к произвольному элементу вектора с помощью индекса. Медленными операциями являются добавление нового элемента в конец массивав случае, когда seze() = capacity(), а также вставка нового элемента в произвольное место вектора. capacity() size() 0 begin() 1 … … … end() Лекция 3 -7. 04. 2014 г. 29
Замечания по поводу реализации (внутреннего устройства) последовательных контейнеров list Контейнер реализован с помощью указателей и каждый узел списка содержит два указателя: «вперед» и «назад» . Включение нового узла в список происходит одинаково быстро в любой его точке: в «хвосте» push_back(), в «голове» - push_front() или в произвольной точке списка – insert(). Однако доступ к произвольному элементу списка с помощью индекса невозможен. NULL elem next prev begin() … NULL end() Лекция 3 -7. 04. 2014 г. 30
Замечания по поводу реализации (внутреннего устройства) последовательных контейнеров deque Реализация контейнера представляет собой комбинацию указателей и массивов фиксированного размера, благодаря чему дек дополнительно к возможностям вектора, таким, как прямой доступ по индексу, добавляет возможность работы с элементами в «голове» дека. Массив указателей begin() Блоки данных фиксированного размера end() Лекция 3 -7. 04. 2014 г. 31
Создание (конструирование) контейнера Все последовательные контейнеры (кроме array) имеют несколько перегруженных конструкторов и могут создаваться разными способами. 1. Создание пустого контейнера с помощью конструктора по умолчанию: #include <vector> #include <deque> #include <list> #include <forward_list> #include <iostream> using namespace std; int main( ) { vector <int> v 1; deque <int> d 1; list <int> l 1; forward_list <int> f 1; cout << "v 1 = ”; for( int i : v 1 ) cout << "d 1 = ”; for( int i : d 1 ) cout << "l 1 = ”; for( int i : l 1 ) cout << "f 1 = ”; for( int i : f 1 ) cout } << " " << i; cout << endl; Лекция 3 -7. 04. 2014 г. 32
Создание (конструирование) контейнера 2. Создание пустого контейнера заданного размера: #include <vector> #include <deque> #include <list> #include <forward_list> #include <iostream> using namespace std; int main( ) { vector <int> v 1(5); deque <int> d 1(5); list <int> l 1(5); forward_list <int> f 1(5); cout << "v 1 = ”; for( int i : v 1 ) cout << "d 1 = ”; for( int i : d 1 ) cout << "l 1 = ”; for( int i : l 1 ) cout << "f 1 = ”; for( int i : f 1 ) cout << } " " << i; cout << endl; Лекция 3 -7. 04. 2014 г. 33
Создание (конструирование) контейнера 3. Создание контейнера заданного размера, заполненного постоянным значением: #include <vector> #include <deque> #include <list> #include <forward_list> #include <iostream> using namespace std; int main( ) { vector <int> v 1(5, 1); deque <int> d 1(5, 2); list <int> l 1(5, 3); forward_list <int> f 1(5, 4); cout << "v 1 = ”; for( int i : v 1 ) cout << "d 1 = ”; for( int i : d 1 ) cout << "l 1 = ”; for( int i : l 1 ) cout << "f 1 = ”; for( int i : f 1 ) cout << " } " << i; cout << endl; Лекция 3 -7. 04. 2014 г. 34
Создание (конструирование) контейнера 4. Создание контейнера, заполненного диапазоном значений: #include <vector> #include <string> #include <iostream> using namespace std; template <class T> void Print(string s, T q) { cout << s; for(auto i : q) cout << " " << i; cout << endl; } int main( ) { vector <int> v({1, 2, 3, 4, 5, 6, 7}); vector <int> v 1(v. begin(), v. begin()+4); vector <int> v 2(v. end()-4, v. end()); vector <int> v 3(v. data(), v. data()+3); vector <int> v 4(&(v. front()), &(v. at(3))); Print("v 1 = ", v 1); Print("v 2 = ", v 2); Print("v 3 = ", v 3); Print("v 4 = ", v 4); int x[] = {10, 11, 12, 13}; vector <int> v 5(x, x+3); Print("v 5 = ", v 5); } Лекция 3 -7. 04. 2014 г. 35
Создание (конструирование) контейнера 5. Конструктор копирования (перемещения): #include <vector> #include <string> #include <iostream> using namespace std; template <class T> void Print(string s, T q) { cout << s; for(auto i : q) cout << " " << i; cout << endl; } int main( ) { vector <int> v 1({1, 2, 3, 4, 5, 6, 7}); vector <int> v 2(v 1); Print("v 1 = ", v 1); Print("v 2 = ", v 2); vector <int> v 3(move(v 1)); Print("v 1 = ", v 1); Print("v 3 = ", v 3); } Лекция 3 -7. 04. 2014 г. 36
Создание (конструирование) контейнера 6. Создание контейнера с помощью списка инициализации: #include <vector> #include <deque> #include <list> #include <forward_list> #include <string> #include <iostream> using namespace std; template <class T> void Print(string s, T q) { cout << s; for(auto i : q) cout << " " << i; cout << endl; } int main( ) { vector <int> v 1({1, 2, 3, 4, 5, 6, 7}); deque <int> d 1 = {10, 11, 12}; list <string> l 1({"one", "two", "three"}); forward_list <double> f 1 = {1. 2, 4. 5, 0. 05}; Print("v 1 = ", v 1); Print("d 1 = ", d 1); Print("l 1 = ", l 1); Print("f 1 = ", f 1); } Лекция 3 -7. 04. 2014 г. 37
Использование операции присваивания для контейнеров Операция присваивания для последовательных контейнеров имеет 3 перегрузки: #include <vector> #include <deque> #include <list> #include <forward_list> #include <string> #include <iostream> using namespace std; template <class T> void Print(string s, T q) { cout << s; for(auto i : q) cout << " " << i; cout << endl; } int main( ) { vector <int> v 1({1, 2, 3, 4, 5, 6, 7}), v 2; deque <int> d 1 = {10, 11, 12}, d 2; list <string> l 1; forward_list <double> f 1; v 2 = v 1; Print("v 1 = ", v 1); Print("v 2 = ", v 2); d 2 = move(d 1); Print("d 1 = ", d 1); Print("d 2 = ", d 2); l 1 = {"one", "two", "three"}; Print("l 1 = ", l 1); f 1 = {1. 2, 4. 5, 0. 05}; Print("f 1 = ", f 1); Лекция 3 -7. 04. 2014 г. } 38
Использование функции assign для контейнеров Функция assign для последовательных контейнеров имеет 3 перегрузки: #include <vector> #include <deque> #include <list> #include <forward_list> #include <string> #include <iostream> using namespace std; template <class T> void Print(string s, T q) { cout << s; for(auto i : q) cout << " " << i; cout << endl; } int main( ) { vector <int> v 1({1, 2, 3, 4, 5, 6, 7}), v 2; deque <int> d 1; list <string> l 1; forward_list <double> f 1; v 2. assign(v 1. begin(), v 1. begin()+4); Print("v 1 = ", v 1); Print("v 2 = ", v 2); d 1. assign(5, 99); Print("d 1 = ", d 1); l 1. assign({"one", "two", "three"}); Print("l 1 = ", l 1); f 1. assign({1. 2, 4. 5, 0. 05}); Print("f 1 = ", f 1); Лекция 3 -7. 04. 2014 г. } 39
Управление размером контейнера function vector deque list forward_list max_size + + + - capacity + - - - resize + + reserve + - - - shrink_to_fit + + - - empty + + shrink_to_fit: capacity -> size Лекция 3 -7. 04. 2014 г. 40
Управление размером контейнера #include <vector> #include <deque> #include <list> #include <forward_list> #include <string> #include <iostream> using namespace std; template <class T> void Print(string s, T q) { cout << s; for(auto i : q) cout << " " << i; cout << endl; } int main( ) { vector <int> v 1({1, 2, 3, 4, 5, 6, 7}); deque <int> d 1; list <string> l 1; l 1. push_front("one"); l 1. push_front("two"); l 1. push_front("three"); forward_list <double> f 1; f 1. emplace_front(1. 2); f 1. emplace_front(4. 5); cout<<"v 1: max_size, size = "<<v 1. max_size()<<", "<< v 1. size()<<endl; Print("v 1 = ", v 1); cout<<"d 1: max_size, size = "<<d 1. max_size()<<", "<< d 1. size()<<endl; cout<<"l 1: max_size, size = "<<l 1. max_size()<<", "<< l 1. size()<<endl; Print("l 1 = ", l 1); cout<<"f 1: max_size = "<<f 1. max_size()<<", "<<endl; Print("f 1 = ", f 1); } Лекция 3 -7. 04. 2014 г. 41
Управление размером контейнера #include <vector> #include <deque> #include <list> #include <forward_list> #include <string> #include <iostream> using namespace std; template <class T> void Print(string s, T q) { cout << s; for(auto i : q) cout << " " << i; cout << endl; } int main( ) { vector <int> v 1({1, 2, 3, 4, 5, 6, 7}); deque <int> d 1; list <string> l 1; l 1. push_front("one"); l 1. push_front("two"); l 1. push_front("three"); forward_list <double> f 1; f 1. emplace_front(1. 2); f 1. emplace_front(4. 5); v 1. resize(4); cout << "v 1: size = " << v 1. size() << endl; Print("v 1 = ", v 1); d 1. resize(5); cout << "d 1: size = " << d 1. size() << endl; Print("d 1 = ", d 1); l 1. resize(5, "blank"); cout << "l 1: size = " << l 1. size() << endl; Print("l 1 = ", l 1); f 1. resize(7, 10. 0); Print("f 1 = ", f 1); } Лекция 3 -7. 04. 2014 г. 42
Управление размером контейнера #include <vector> #include <iostream> using namespace std; int main( ) { vector <int> v 1; v 1. push_back( 10 ); v 1. push_back( v 1. resize( 10, 40 ); cout << "v 1: size = " << v 1. size( v 1. resize( 6, 50 ); cout << "v 1: size = " << v 1. size( v 1. reserve( 20 ); cout << "v 1: size = " << v 1. size( v 1. reserve( 5 ); cout << "v 1: size = " << v 1. size( v 1. shrink_to_fit(); cout << "v 1: size = " << v 1. size( v 1. clear( ); cout << "v 1: size = " << v 1. size( } 20 ); v 1. push_back( 30 ); ) << ”, capacity = “<<v 1. capacity( ) << endl; Лекция 3 -7. 04. 2014 г. 43
Итераторы function vector deque list forward_list begin + + cbegin + + rbegin + + + - crbegin + + + - end + + cend + + rend + + + - crend + + + - before_begin - - - + cbefore_begin - - - + Лекция 3 -7. 04. 2014 г. 44
Итераторы #include <vector> #include <deque> #include <list> #include <forward_list> #include <string> #include <iostream> using namespace std; template <class T> void Print(string s, T q) { cout << s; for(auto i : q) cout << " " << i; cout << endl; } int main( ) { forward_list <string> f 1 = {"one", "two", "three"}; f 1. insert_after( f 1. before_begin(), "four" ); Print("f 1 = ", f 1); f 1. insert_after( f 1. begin(), "five" ); Print("f 1 = ", f 1); } Лекция 3 -7. 04. 2014 г. 45
Доступ к элементам function vector deque list forward_list operator[] + + - - at + + - - front + + back + + + - data + - - - Лекция 3 -7. 04. 2014 г. 46
Доступ к элементам #include <vector> #include <deque> #include <list> #include <forward_list> #include <string> #include <iostream> using namespace std; template <class T> void Print(string s, T q) { cout << s; for(auto i : q) cout << " " << i; cout << endl; } int main( ) { vector <int> v 1({1, 2, 3, 4, 5, 6, 7}); deque <int> d 1 = {10, 11, 12}; list <string> l 1({"one", "two", "three"}); forward_list <double> f 1 = {1. 2, 4. 5, 0. 05}; Print("v 1 = ", v 1); v 1[3] = 99; v 1. at(4) = 100; Print("v 1 = ", v 1); *(v 1. data()+1) = 77; Print("v 1 = ", v 1); Print("d 1 = ", d 1); d 1[0] = d 1[2]; d 1. at(1) = 55; Print("d 1 = ", d 1); Print("l 1 = ", l 1); l 1. front() = "six"; Print("l 1 = ", l 1); l 1. back() = "seven"; Print("l 1 = ", l 1); Print("f 1 = ", f 1); f 1. front() = 0. 002; Print("f 1 = ", f 1); } Лекция 3 -7. 04. 2014 г. 47
Модификация контейнера function vector deque list forward_list emplace_back + + + - push_back + + + - pop_back + + + - emplace + + + - insert + + + - erase + + + - swap + + clear + + emplace_front - + + + push_front - + + + pop_front - + + + emplace_after - - - + insert_after - - - + erase_after - - - + Лекция 3 -7. 04. 2014 г. 48
Функции, позволяющие модифицировать содержимое последовательного контейнера Продолжим рассмотрение функций для работы с последовательными контейнерами. На предыдущем слайде представлены функции, позволяющие модифицировать содержимое ранее созданного последовательного контейнера. Две из них – clear() и swap() применимы ко всем видам таких контейнеров. template <class T> void Print(string s, T q) { cout << s; for(auto i : q) cout << " " << i; cout << endl; } int main( ) { vector<int> v 1(3, 100), v 2({1, 2, 3, 4, 5}); Print("v 1 = ", v 1); Print("v 2 = ", v 2); v 1. swap(v 2); Print("v 1 = ", v 1); Print("v 2 = ", v 2); v 1. clear(); Print("v 1 = ", v 1); list<string> ls 1(3, "sample"), ls 2({"mon", "tue", "wed", "thu", "fri"}); Print("ls 1 = ", ls 1); Print("ls 2 = ", ls 2); ls 1. swap(ls 2); Print("ls 1 = ", ls 1); Print("ls 2 = ", ls 2); ls 1. clear(); Print("ls 1 = ", ls 1); return 0; } Лекция 3 -7. 04. 2014 г. 49
Функции, позволяющие модифицировать содержимое последовательного контейнера Следующие три функции: erase(), insert() и emplace() позволяют вносить изменения в произвольном месте контейнера (за исключением forward_list). Функция erase() удаляет один или несколько элементов контейнера, а функции insert() и emplace() производят вставку: insert() позволяет вставить один или несколько элементов, а emplace() – вставить один элемент. Различие между insert() и emplace() при вставке одиночного элемента состоит в том, что в emplace() конструирует новый элемент «на лету» – ему передается набор параметров, для которых вызывается подходящий конструктор, а в insert() нужно передать уже существующий элемент. (!!!) В функцию emplace() также можно передать уже существующий элемент и в этом случае будет вызван конструктор копирования или конструктор перемещения. Лекция 3 -7. 04. 2014 г. 50
Пример с erase(), insert() и emplace() struct A { string a; A(string a_) : a(a_) {} A(const A& x) : a(x. a) { cout << "copyn"; } // copy constructor A(A&& x) { *this = move(x); cout << "moven"; } // move constructor }; int main( ) { list<A> v 1; A z("five"); auto i = v 1. begin(); i = v 1. emplace(i, "one"); cout << "a = " << i->a << endl; //i = v 1. insert(i, "five"); //i = v 1. insert(i, A("five")); i = v 1. insert(i, z); cout << "a = " << i->a << endl; i = v 1. emplace(i, A("seven")); cout << "a = " << i->a << endl; v 1. erase(i++, ++i); if(v 1. empty()) cout << "container is empty" << endl; else cout << "a = " << i->a << endl; return 0; } Лекция 3 -7. 04. 2014 г. 51
Функции, позволяющие модифицировать «хвост» последовательного контейнера Для контейнеров vector, deque и list применимы функции emplace_back(), push_back() и pop_back(), позволяющие производить добавление и удаление элементов, расположенных в конце последовательности (в «хвосте» ). struct A { string a; A(string a_) : a(a_) {} }; int main( ) { list<A> v 1 = {A("one"), A("two")}; v 1. emplace_back("three"); v 1. push_back(A("four")); for(auto i : v 1) cout << i. a << " "; cout << endl; v 1. pop_back(); for(auto i : v 1) cout << i. a << " "; cout << endl; return 0; } Лекция 3 -7. 04. 2014 г. 52
Функции, позволяющие модифицировать «голову» последовательного контейнера Для контейнеров deque, list и forward_list применимы функции emplace_front(), push_front() и pop_front(), позволяющие производить добавление и удаление элементов, расположенных в начале последовательности (в «голове» ). struct A { string a; A(string a_) : a(a_) {} }; int main( ) { forward_list<A> v 1 = {A("one"), v 1. emplace_front("three"); v 1. push_front(A("four")); for(auto i : v 1) cout << i. a << v 1. pop_front(); for(auto i : v 1) cout << i. a << return 0; } A("two")}; " "; cout << endl; v 1. pop_front(); " "; cout << endl; Лекция 3 -7. 04. 2014 г. 53
Функции, специфичные для однонаправленного списка Для контейнера forward_list применимы специфичные для него функции emplace_after(), insert_after() и erase_after(), позволяющие производить добавление и удаление элементов, расположенных после указанного элемента. struct A { string a; A(string a_) : a(a_) {} }; int main( ) { forward_list<A> v 1 = {A("one"), A("two")}; v 1. emplace_after(v 1. begin(), "three"); auto i = v 1. begin(); v 1. insert_after(++i, A("four")); for(auto i : v 1) cout << i. a << " "; cout << endl; i = v 1. begin(); v 1. erase_after(++i); for(auto i : v 1) cout << i. a << " "; cout << endl; return 0; } Лекция 3 -7. 04. 2014 г. 54
Списковые операции function list forward_list splice + - remove + + remove_if + + unique + + merge + + sort + + reverse + + splice_after - + Лекция 3 -7. 04. 2014 г. 55
Операции над списками Для контейнеров list и forward_list (т. е. для списков) применяется несколько специфичных функций, перечень которых приведен на предыдущем слайде. Функции remove() и remove_if() позволяют удалять элементы списка: // предикат реализован как функция: bool single_digit (const int& value) { return (value<10); } // предикат реализован как функтор: class is_odd_class{ public: bool operator() (const int& value) {return (value%2)==1; } } is_odd_object; int main( ) { forward_list<int> mylist = {7, 80, 7, 2, 5, 15, 85, 52, 6}; Print("mylist = ", mylist); mylist. remove(7); // 80 2 5 15 85 52 6 Print("mylist = ", mylist); mylist. remove_if (single_digit); // 80 15 85 52 Print("mylist = ", mylist); mylist. remove_if (is_odd_object); // 80 52 Print("mylist = ", mylist); return 0; } Лекция 3 -7. 04. 2014 г. 56
Операции над списками Функция unique() также позволяют удалять элементы списка по определенному условию: // предикат реализован как функция: bool same_integral_part (double first, double second) { return ( int(first)==int(second) ); } // предикат реализован как функтор: class is_near_class{ public: bool operator() (double first, double second) { return (fabs(first-second)<5. 0); } } is_near_object; int main () { forward_list<double> mylist = { 15. 2, 73. 0, 3. 14, 15. 85, 69. 5, 73. 0, 3. 99, 15. 2, 69. 2, 18. 5 }; mylist. sort(); Print("mylist = ", mylist); mylist. unique (same_integral_part); Print("mylist = ", mylist); mylist. unique (is_near_object); Print("mylist = ", mylist); return 0; } Лекция 3 -7. 04. 2014 г. 57
Операции над списками Функция reverse() позволяет реверсировать список, т. е. изменить порядок следования элементов на противоположный, а функция sort() выполняет сортировку списка по различным критериям: template <class T> void Print(string s, T q) { cout << s; for(auto i : q) cout << " " << i; cout << endl; } int main( ) { forward_list<int> mylist = {7, 80, 7, 2, 5, 15, 85, 52, 6}; Print("mylist = ", mylist); mylist. reverse(); Print("mylist = ", mylist); mylist. sort(); Print("default sort (operator<): mylist = ", mylist); mylist. sort(std: : greater<int>()); Print("sort with std: : greater(): mylist = ", mylist); return 0; } Лекция 3 -7. 04. 2014 г. 58
Операции над списками Функция merge() производит слияние заранее отсортированных списков: int main( ) { forward_list<string> first = {"mon", "tue", "wed", "thu", "fri"}; forward_list<string> second = {"red", "orange", "yellow", "green"}; forward_list<string> third = {"one", "two", "three", "four", "five"}; first. sort(); second. sort(); Print("first = ", first); Print("second = ", second); first. merge(move(second)); Print("first = ", first); first. sort(greater<string>()); third. sort(greater<string>()); Print("first = ", first); Print("third = ", third); first. merge(move(third), greater<string>()); Print("first = ", first); return 0; } Лекция 3 -7. 04. 2014 г. 59
Операции над списками Функция splice() применима только для list и она производит вставку элементов в список из другого списка: int main( ) { list<int> mylist 1 = {1, 2, 3, 4}, mylist 2 = {10, 20, 30}; Print("mylist 1 = ", mylist 1); Print("mylist 2 = ", mylist 2); auto it = mylist 1. begin(); ++it; mylist 1. splice (it, mylist 2); // "it" по прежнему указывает на 2, т. е. на 5 -й элемент Print("mylist 1 = ", mylist 1); Print("mylist 2 = ", mylist 2); mylist 2. splice(mylist 2. begin(), mylist 1, it); // "it" имеет недопустимое значение Print("mylist 1 = ", mylist 1); Print("mylist 2 = ", mylist 2); it = mylist 1. begin(); advance(it, 3); // "it" указывает на 30 mylist 1. splice(mylist 1. begin(), mylist 1, it, mylist 1. end()); Print("mylist 1 = ", mylist 1); return 0; } Лекция 3 -7. 04. 2014 г. 60
Операции над списками Функция splice_after() применима только для forward_list и она также производит вставку элементов в список из другого списка: int main () { forward_list<int> first = {1, 2, 3}, second = {10, 20, 30}; Print("first = ", first); Print("second = ", second); auto it = first. begin(); first. splice_after(first. before_begin(), move(second)); // "it" по прежнему указывает на 1, т. е. на 4 -й элемент Print("first = ", first); Print("second = ", second); second. splice_after(second. before_begin(), move(first), first. begin(), it); Print("first = ", first); Print("second = ", second); first. splice_after(first. before_begin(), move(second), second. begin()); Print("first = ", first); Print("second = ", second); return 0; } Лекция 3 -7. 04. 2014 г. 61
Лекция-2.08.ppt