Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
лекції 2012-2013ооп.docx
Скачиваний:
1
Добавлен:
01.04.2025
Размер:
6.61 Mб
Скачать

Лекція № 8 Тема 8. Бібліотека стандартних шаблонів stl (Standard Template Library)

Основні концепції STL

План лекції

1.Бібліотека стандартних шаблонів - STL (призначення, основні можливості, сфера застосування).

2.Стандартні потоки і потокові класи.

3.Стрічки (основні операції та функції; переваги порівняно із C - стрічками).

4.Поняття про контейнери, ітератори, функціональні об' єкти та алгоритми STL.

Зміст лекції

##include <vector>

##include <list>

##include <deque>

using namespace std:

Контейнер вектор є аналогом звичайного масиву, за винятком того, що він автоматично виділяє і звільняє пам'ять в міру необхідності. Контейнер ефективно обробляє довільну вибірку елементів з по-мощью операції індексації [] або методу at. Проте вставка елементу в будь-яку позицію, окрім кінця вектору, неефективна. Для цього потрібно буде зрушити усі наступні елементи шляхом копіювання їх значень. З цієї ж причини неефективним є видалення будь-якого елементу, окрім останнього.

Контейнер список організовує зберігання об' єктів у вигляді двозвязкового списку. Кожен елемент списку містить три поля: значення елементу, покажчик на передуючий, і покажчик на наступний елементи списку. Вставка і видалення працюють ефективно для будь- якої позиції елементу в списку. Проте список не підтримує довільного доступу до своїх елементів: наприклад, для вибірки n -го елементу треба послідовно вибрати попередні n - 1 елементів.

Контейнер двостороння черга {дек) багато в чому аналогічний вектору, елементи зберігаються в безперервній області пам'яті. Але на відміну від вектору двостороння черга ефективно підтримує вставку і видалення першого елементу (так само, як і останнього).

Існує п'ять способів визначити об'єкт для послідовного контейнера.

Створити порожній контейнер:

vector<int> vecl: list<string> list1:

Створити контейнер заданого розміру і ініціалізувати його елементи зна-чениями за умовчанням:

vector<string> vec1(100) : list<double> list1(20) :

Створити контейнер заданого розміру і ініціалізувати його елементи вказаним значенням:

vector<string> vecl(100. ''Hello"!) : deque<int> decl(300. - 1) :

Створити контейнер і ініціалізувати його елементи значеннями діапазону [first, last) елементів іншого контейнера:

int arr[7] = {15. 2. 19. - 3. 28. 6. 8}: vector<int> v1(arr. arr + 7) : list<int> lst(v1.beg() + 2. v1.end()) :1

Створити контейнер і ініціалізувати його елементи значеннями елементів іншого однотипного контейнера :

vector<int> v1:

// // додати в v1 елементи vector<int> v2(v1) :

Для вставки і видалення останнього елементу контейнера будь-якого з трьох розглядаючих класів призначені методи push_back() і pop_back(). Крім того, список і черга (але не вектор) підтримують операції вставки і видалення першого елементу контейнера push_front() і pop_front(). Врахуйте, що методи pop_back() і pop_front() не повертають видалене значення. Щоб рахувати перший елемент, використовується метод front(), а для прочитування останнього елементу - метод bаск().

Шаблони функцій та класів.

В процесі роботи над програмами, що використовують контейнери, часто прихо-дится виводити на екран їх поточний вміст. Приведемо шаблон функції, що вирішує цю задачу для будь-якого типу контейнера, :

template <class Т> void print(T& cont){

typename T:: const_iterator p = cont.begin() : if (cont.empty())

cout " "Container is empty".: for (p: p != cont.end() : ++p) cout " *p " ' ': cout " endl:

}

Зверніть увагу на службове слово typename, з якого починається оголошення ітератора р. Річ у тому, що бібліотека STL "знає", що Т::iterator - це деякий тип, а компілятор C++ такого знання не має. Тому без typename нормальні компілятори фіксують помилку.

Тепер можна користуватися функцією print(), включаючи її визначення в початковий файл з програмою, як, наприклад, в наступному експерименті з чергою:

##include <iostream>

##include <deque> using namespace std:

/* ... /* .. визначення функції print .. */ int main() {

deque<int> dec:

print(dec)

//

Container

dec.push_back(4) :

print(dec)

//

4

dec.push_front(3) :

print(dec)

//

3 4

dec.push_back(5) :

print(dec)

//

3 4 5

dec.push_front(2) :

print(dec)

//

2 3 4 5

dec.push_back(6) :

print(dec)

//

2 3 4 5 6

dec.push_front(1) :

print(dec)

//

1 2 3 4 5

return 0:

Адаптери контейнерів

Спеціалізовані послідовні контейнери - стек, черга і черга з пріоритетами - не є самостійними контейнерними класами, а реалізовані на основі розглянутих вище класів, тому вони називаються адаптерами контейнерів.

Стек

Шаблонний клас stack (заголовний файл <stack>) визначений як

template <class Т. class Container = deque<T> > class stack { /* .. */ }:

де параметр Container задає клас-прототип. За умовчанням для стека прототипом є клас deque. Сенс такої реалізації полягає в тому, що спеціалізований клас просто перевизначає інтерфейс класу-прототипу, обмежуючи його тільки тими методами, які потрібні новому класу. У таблиці. 6.5 показано, як сформований інтерфейс класу stack з методів класу-прототипу.

Таблиця 6.5. Інтерфейс класу stack

Методи класу stack

Методи класу-прототипу

push()

push_back()

pop ()

pop_back()

top()

back()

empty()

empty()

size()

size()

Відповідно до свого призначення стек не лише не дозволяє виконати довільний доступ до своїх елементів, але навіть не дає можливості покрокового переміщення, у зв'язку з чим

концепція ітераторів в стеку не підтримується. Нагадуємо, що метод pop () не повертає видалене значення. Щоб рахувати значення на вершині стека, використовується метод top().

Приклад роботи із стеком - програма вводить з файлу числа і виводить їх на екран в зворотному порядку:

int main() {

ifstream in ("inpnum.txt") : stack<int> s: int x:

while (in " x) s.push(x) :

while (!s.empty()){

cout " s.top() " ' ': s.pop() :

}

return 0:

}

Оголошення stack<int> s створює стек на базі двосторонньої черги (за умовчанням). Якщо з якихось причин нас це не влаштовує і ми хочемо створити стек на базі списку, то оголошення виглядатиме таким чином:

stack<int. list<int> > s: