Сегодня мы поговорим о достаточно полезной штуке в C++ - динамическом массиве vector. Но для начала нужно сказать несколько слов о шаблонах в С++.

Обобщенное программирование

Обобщенное программирование - это парадигма программирования, поддерживается такими языками, как C++, Java, C#, Object Pascal. Суть заключается в таком описании данных и алгоритмов, которые можно применить к нескольким типам данных без изменения описания. Шаблон в C++ - средство, созданное для описания обобщенных алгоритмов, функций, классов.

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

template<typename T>
void div(T a, T b); // прототип

template<typename T>
void div(T a, T b)
{
	cout <<  a / b;
};

Теперь можем вызвать функцию div, при этом указав тип в угловых скобках.

div<double>(a, b);

Сообщество программистов заранее позаботилось, и чтобы не писать каждый раз шаблоны, они разработали STL (Standart Template Library - Стандартная Биоблиотека Шаблонов).

Standart Template Library (STL, стандаотная библиотека шаблонов) - это особый набор обобщенных алгоритмов и контейнеров. Когда мы говорим “обобщенные” мы подразумеваем, что данные алгоритмы/контейнеры могут работать с любым типом данных, в том числе и с типом, который определил пользователь.

STL является мощной составляющей частью языка C++. В дальнейшем мы будем рассматривать контейнеры из этой библиотеки.

std::vector

Начнем мы с vector. Чтобы лучше понять, что такое vector, представьте себе обычный массив. А теперь представьте что мы можем изменять его размер. Это означает, что vector - это динамический массив. Данный шаблон расположен в заголовчном файле . Его инициализация выглядит следующим образом:

#include <iostream>
#include <vector>

using namespace std;

int main()
{
	vector<int> vec;
	return 0;
}

У vector имеются свои методы. Рассмотрим некоторые из них.

push_back(…) Вставка элемента в конец вектора
pop_back(…) Очищает последний элемент вектора
resize(…) Изменяет размер вектора
empty(…) Возвращает true, если вектор пуст
vector<int> vec;
vec.push_back(15); // добавили 15 в конец
vec.pop_back(); // очистили последний элемент
if (vec.empty()) // вектор пустой?
{
	vec.resize(100); // увеличили размер до 100
}
cout << vec.size(); // вывод размера

Также можем заполнить вектор в цикле:

vector<int> vec;
int size;
cin >> size;
for (int i = 0; i < size; i++)
{
	int temp;
	cin >> temp;
	vec.push_back(temp);
}

К заполненному вектору мы можем обращаться как к массиву:

vector<int> vec = { 2,3,4 };
cout << vec[1]; // correct
cout << vec[500]; // error: vector subscript out of range

Обращение к несуществующей ячейке вектора приведет к ошибке.

Некоторое время назад мы говорили об итераторах. Напомним, что итератор - такая вещь, предоставляющая доступ к элементам коллекции(вектору в данном случае). Итераторы создаются при помощи таких стандартных методов как begin() и end(). Функция begin() возвращает указатель на первый элемент, а end() — на воображаемый несуществующий элемент, следующий за последним.

Пример: мы ввели число элементов последовательности и саму последовательность. Нужно найти её сумму.

long long size, sum = 0;
vector<long long> vec;
vector<long long>::iterator iter; // объявляем итератор
cin >> size;
for (long long i = 0; i < size; i++)
{
	int temp;
	cin >> temp;
	vec.push_back(temp);
}
for (iter = vec.begin(); iter != vec.end(); iter++) // итерируемся
{
	sum += *iter; // * - операция разыменования
}
cout << sum;

Цикл for, основанный на диапазоне

На самом деле, код написанный нами выше, можно переписать в более удобночитаемый. Это можно достигнуть при помощи for - each.

long long size, sum = 0;
vector<long long> vec;
	
cin >> size;
for (long long i = 0; i < size; i++)
{
	int temp;
	cin >> temp;
	vec.push_back(temp);
}
	
for (auto x : vec) // цикл for на диапазоне
{
	sum += x;
}

cout << sum;

Как вы видите, в приведенном коде мы не соприкоснулись с указателями(на первый взгляд). Однако то, что мы написали выше (vector::iterator iter) как раз спрятано в auto. Вообще говоря, auto - это автоматическое выведение типа из инициализации. Таким образом, мы прошлись по всему вектору и посчитали его сумму.