STL вводить ряд понять і структур даних, які майже у всіх випадках дозволяють сильно спростити програмний код. Вводяться наступні категорії понять:
контейнер - Зберігання набору об'єктів в пам'яті.
Итератор - засіб доступу до вмісту окремих об'єктів в контейнері.
алгоритм - Визначення найбільш стандартних обчислювальних процедур на контейнерах.
адаптер - Адаптація основних зас категорій для забезпечення найбільш уживаних інтерфейсів (таких як стек або черга).
Функтор (функціональний об'єкт) - Приховування функції в об'єкті для використання її іншими категоріями.
бібліотека STL - Це дуже велика область. Її опису присвячені цілі окремі книги (одна з кращих книг російською мовою, достатня для освоєння STL в деталях, показана в кінці тексту). Ми ж, в силу початкового рівня знайомства, розглянемо техніку STL на інтуїтивно ясних прикладах.
Синтаксис STL заснований на використанні таких синтаксичних конструкцій мови C ++ як шаблони (шаблони) класів і шаблони функцій. Але для успішного застосування техніки STL зовсім не обов'язково глибоке розуміння техніки шаблони.
центральним поняттям STL, навколо якого крутиться все інше, це контейнер (ще використовують термін колекція). Контейнер - це набір певної кількості однотипних елементів, упакованих в контейнер певним чином. Найпростішим прототипом контейнера в класичному мовою C ++ є массив. той спосіб, яким елементи упаковуються в контейнер, визначає тип контейнера і особливості роботи з елементами в такому контейнері. STL вводить цілий ряд різноманітних типів контейнерів:
послідовні контейнери - вектор (vector), двусвязний список (list), ДЕК (deque);
асоціативні контейнери - безлічі (комплект і мультімножество ), хеш-таблиці (карта і MultiMap);
псевдо-контейнери - бітові маски (BitSet), строки (string і wstring), массивы (valarray);
Ми послідовно розглянемо на прикладах використання основних контейнерів, переходячи від більш простих до складних. Найпростішим типом з них є вектор. Близьким прототипом вектора є масив С ++. Але розмір вектора в будь-який час може динамічно змінюватися операціями додавання (метод push_back()) або видалення елемента. Також, як і для масиву, ми можемо звернутися до довільного елементу вектора операцією індексації [n]. Це вже і є перший, поверхневий шар знань про vector, який дозволяє нам почати з ним працювати:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | #include <iostream> #include <vector> #include <climits> using namespace std; // вывод на экран значений ёмкости вектора // его размера и элементов void put(const vector<float>& v) { cout << "capacity=" << v.capacity() << ", size=" << v.size() << " : "; for (int i = 0; i < v.size(); i++) cout << v[i] << " "; cout << endl; } // перегруженный оператор, добавляющий к вектору ещё n // последовательных значений натуральных чисел vector<float>& operator +=(vector<float>& v, int n) { float last = v[v.size() - 1]; for (int i = 0; i < n; i++) v.push_back(last + i + 1); return v; } int main(void) { float data[] = { 1, 2, 3, 4, 5, 6, 7 }; int n = sizeof(data) / sizeof(data[0]); vector<float> array(data, data + n); cout << "max_size=" << array.max_size() << " ((INT_MAX+1)/2)=" << ((int)INT_MAX + 1) / 2 << endl; put(array); put(array += 2); put(array += 6); return 0; } |
опис vector<float> (це і є згадуваний раніше template в описі класу) оголошує в коді об'єктarray: вектор елементів типу float.
Далі ми бачимо такі методи класу vector<float>, як max_size() - Максимально можлива довжина векторів взагалі (константа реалізації); size() - Поточний розмір (число елементів) вектора; ємність() - Поточна ємність вектора (максимальне число елементів, яке може бути вміщено в вектор в поточному його розміщенні). Виконання цього фрагмента дасть щось приблизно наступне (деталі можуть відрізнятися в залежності від реалізації):
Тут видно досить цікаве поведінку вектора (в цьому і його сенс): як тільки при додаванні чергового елемента, ємності вектора стає недостатньо, робиться нове розміщення вектора, резервуючи для нього подвоєну ємність (з запасом, щоб наступне ж додавання нового елемента не зажадало відразу ж нового перерозміщення).
Таким чином ми отримали еквівалент масиву C ++, розмір якого (size()) змінюється в довільних межах від декількох одиниць до мільйонів елементів. звернемо увагу (це дуже важливо), що збільшення розміру вектора досягається не індексацією за межі його поточного розміру, і "zatalkivaniem» (метод push_back()) нового елемента в кінець вектора. Інший спосіб змінити розмір вектора - це викликати методи змінити розмір(). Саме тому, для вектора передбачено 2 різних способу індексації: операция [n] і метод-функція at(n). метод at() перевіряє поточний розмір вектора size(), і при індексації за його кордон спрацьовуєвиняток (це помилка!). навпаки, операція індексації не перевіряє кордон, що небезпечно, але зате це швидше.
zliys9