Предыдущий пост -
Следующий пост -

std::vector

Рубрика: Контейнеры, Дата: 15 May, 2013, Автор:
Tags: ,

Здорова господа!

Рассмотрим сейчас std::vector. Просто охота его рассмотреть, все функции как, что работает.

Посмотрим, что такое vector как его использовать? vector – это стандартный последовательный контейнер. Находится он в заголовочном файле <vector>. Чтобы начать его использовать нужно в файле прописать:

#include <vector>
using std::vector;

Все мы теперь можем в файле спокойно создавать вектора.

Теперь давайте рассмотрим как можно создать вектора, от примерчик кода:

        //создается вектор из 10 элементов равных 0
	vector<int> vec(10);//элементы равны нулями

	//создается вектор из 11 элементов равных 3
	vector<int> vec1(11,3);//элементы равны трем

	//создание вектора с помощью итераторов
	vector<int> vec2(vec1.begin(), vec1.end());

	//создание вектора конструктор копирования
	vector<int> vec3(vec);//копия вектора vec

	//создание пустого вектора
	vector<int> vec4; //пустой вектор

Это небольшие примерчики как можно создавать вектора.

 

А теперь давайте рассмотрим какие операции поддерживает vector. Он поддерживает операцию индексации operator[]. (произвольного доступа).

        vector<int> vec(10);
	for(int i=0;i<vec.size();i++)
	{
		vec[i]=i;
		cout <<vec[i]<<' ';
	}
	cout <<endl;

Мы здесь использовали функцию size() которая возвращает количество элементов которые находятся в векторе, возвращает размер вектора.

Итераторы:

vector поддерживает итераторы прямой и обратный.

vector::iterator и vector::reverse_iterator

vector<int> vec(10);
	int count(0);

	vector<int>::iterator it=vec.begin();
	for(;it!=vec.end();++it)
	{
		*it=count++;
		cout <<*it<<' ';
	}
	cout <<endl;

	vector<int>::reverse_iterator rit=vec.rbegin();
	for(;rit!=vec.rend();++rit)
	{
		cout <<*rit<<' ';
	}
	cout <<endl;

Константные итераторы используются аналогично не константным.

vector::const_iterator и vector::const_reverse_iterator

vector<int> vec(10);
	int count(0);

	for(int i=0;i<vec.size();i++)
		vec[i]=i;

	vector<int>::const_iterator c_it=vec.begin();
	for(;c_it!=vec.end();++c_it)
		cout <<*c_it<<' ';
	cout <<endl;

	vector<int>::const_reverse_iterator c_r_it=vec.rbegin();
	for(;c_r_it!=vec.rend();++c_r_it)
		cout <<*c_r_it<<' ';
	cout <<endl;

 

vector::operator=()

Так же vector имеет operator= , а это означает, что одному вектору можно присвоить другой вектор, то есть отак:

        vector<int> vec(10,7);//10 элементов, значение 7
	vector<int> vec1;//пустой вектор
	cout <<vec1.size()<<' '<<vec.size()<<endl;//0 10
	vec1=vec;
	cout <<vec1.size()<<' '<<vec.size()<<endl;//10 10

 

Теперь давайте рассмотрим какие есть еще функции для использования vector.

Функции показывающие состояние вектора размер и т.д.

vector::size():

Это функция которая возвращает размер вектора. Мы уже выше ее использовали. Так давайте еще раз приведем примерчик по ее использованию.

        vector<int> vec(10,7);//10 элементов, значение 7
	vector<int> vec1;//пустой вектор
	cout <<vec1.size()<<' '<<vec.size()<<endl;//0 10

 

vector::max_size()

Это функция которая возвращает максимальный размер вектора который возможен на данной машине.

        vector<int> vec(10,7);//10 элементов, значение 7
	vector<int> vec1;//пустой вектор
	cout <<vec1.max_size()<<' '<<vec.max_size()<<endl;//

 

vector::resize()

        vector<int> vec(10);//10 элементов, значение 7

	for(int i=0;i<10;i++)
	{
		vec[i]=i;
		cout <<vec[i]<<' ';
	}
	cout <<endl;
	cout <<"vec.size()= "<<vec.size()<<endl;

	vec.resize(5);
	for(int i=0;i<vec.size();i++)
		cout <<vec[i]<<' ';
	cout <<endl;
	cout <<"vec.size()= "<<vec.size()<<endl;

Как мы видим из листинга выше, то resize() уменьшает размер вектора с конца, то есть последние элементы удаляются.

vector::capacity()

Я в общем разобрался. На форуме мне подсказали capacity() возвращает емкость резерва, то есть памяти которая зарезервирована но не доступна. Это делается специально чтобы не выделять каждый раз заново память, а просто дать доступ к уже выделенной и зарезервированной, но не доступной памяти.

Не вижу разницы с size() то же самое вроде выводит. Вот примерчик:

        vector<int> vec(30,444);//10 элементов, значение 7
	cout <<"vec.capacity()= "<<vec.capacity()<<endl;//30
	cout <<"vec.size()= "<<vec.size()<<endl;

 

vector::empty()

Если вектор пуст, то возвращается false, если не есть элементы то true.

        vector<int> vec(30,444);//10 элементов, значение 7
	vec.clear();
	if(vec.empty())
		cout <<"vector pyct"<<endl;//выведет эту строку
	else
		cout <<"ect6 elementu"<<endl;

 

vector::reserve()

Эта функция выделяет память для резерва capacity() , то есть reserve только увеличивает память. capacity() никогда не может быть меньше size(), а только может быть больше.

В описании написано типо изменяет capacity (мощьность). Щас проверим.

        vector<int> vec(30,444);//10 элементов, значение 7
	cout <<"vec.size()= "<<vec.size()<<endl;
	cout <<"vec.capacity()= "<<vec.capacity()<<endl;
	vec.reserve(35);//увеличивает емкость 
	cout <<"vec.size()= "<<vec.size()<<endl;
	cout <<"vec.capacity()= "<<vec.capacity()<<endl;

Оно увеличивает capacity, но увы не уменьшает.

 

vector::shrink_to_fit()

Видимо эта функция делает равным резерв и реально доступную память, равняет их просто.

В общем эта от фигня возвращает capacity в исходное положение.

        vector<int> vec(30,444);//10 элементов, значение 7
	cout <<"vec.size()= "<<vec.size()<<endl;//30
	cout <<"vec.capacity()= "<<vec.capacity()<<endl;//30
	vec.reserve(40);//увеличивает емкость 
	cout <<"vec.size()= "<<vec.size()<<endl;//30
	cout <<"vec.capacity()= "<<vec.capacity()<<endl;//40
	vec.shrink_to_fit();//ставит емкость в исходное значение 
	cout <<"vec.size()= "<<vec.size()<<endl;//30
	cout <<"vec.capacity()= "<<vec.capacity()<<endl;//30

 

Элементы доступа:

vector::oparetor[]

Я уже вроде делал выше на него пример но еще раз сюда скину видно я ошибся по быстрому заранее написал.

	vector<int> vec(10);//10 элементов
	for(int i=0;i<vec.size();i++)
	{
		vec[i]=i;
		cout <<vec[i]<<' ';
	}
	cout <<endl;

 

vector::at()

Это доступ с проверкой выхода за границы, если мы выходим за границы, то выбрасывается out_of_range. Щас приведу примерчик:

	vector<int> v(4);
	try
	{
		v.at(4)=3;
	}
	catch( out_of_range& e)
	{
		cout <<"out_of_range"<<endl;
	}

 

vector::front()

Эта функция показывает доступ к первому элементу вектора.

	vector<int> v(4);
	for(int i=0;i<v.size();i++)
		v[i]=i;

	cout <<v.front()<<endl;//0

 

vector::back()

Это доступ к последнему элементу вектора.

	vector<int> v(4);
	for(int i=0;i<v.size();i++)
		v[i]=i;

	cout <<v.back()<<endl;//3

 

vector::data()

Мы его не будем проверять потому, что это стандарт С++ 2011. Все таки разберем data(). Я так посмотрел это функция которая возвращает указатель на массив реализации вектора. То есть вроде адрес возвращает. Для меня эта функция конечно новая. Я с ней не сталкивался, поэтому щас попробуем реализовать примерчик мб станет более ясно, что да как.

	vector<int> vec(4,5);
	int* ptr=vec.data();//ссылка на массив представление вектора.

	for(int i=0;i<vec.size();i++)
	{
		cout <<"ptr["<<i<<"]= "<<ptr[i]<<endl;
		cout <<"vec["<<i<<"]= "<<vec[i]<<endl;
		ptr[i]=i;
		cout <<"vec["<<i<<"]= "<<vec[i]<<endl;
	}

Как видим vec.data() просто возвращает ардес на ячейку представления vec, то есть на массив который в нем хранится.

Теперь рассмотрим функции модификаторы.

vector::assign()

Ну я не знаю, что эта функция делает. Щас попытаемся разобраться создавая пример. Все я разобрался с этой функцией assign переводится как назначать. Эта функция просто назначает вектор, как бы его инициализирует. Можно так сказать.
От примерчик демонстрации возможности assign():

	vector<int> vec;
	vector<int> vec1;
	vector<int> vec2;

	vec.assign(10,5);//10 элементов значение по 5
	vec1.assign(vec.begin()+1,vec.end()-1);//8 элементов по 5

	int mass[3]={1,3,4};
	vec2.assign(mass,mass+3);
	//vuvodim razmeru
	cout <<"vec.size()= "<<vec.size()<<endl;
	cout <<"vec1.size()= "<<vec1.size()<<endl;
	cout <<"vec2.size()= "<<vec2.size()<<endl;

	//вывод содержимого векторов
	for(int i=0;i<vec.size();i++)
		cout <<vec[i]<<' ';
	cout <<endl;

	for(int i=0;i<vec1.size();i++)
		cout <<vec1[i]<<' ';
	cout <<endl;

	for(int i=0;i<vec2.size();i++)
		cout <<vec2[i]<<' ';
	cout <<endl;

 

vector::push_back()

С этой функцией мне конечно все ясно, она добавляет элементы в конец вектора. Добавление происходит с увеличением резерва capacity в два раза когда он заканчивается либо в полтора, это зависит от реализации, в visual studio 2010 увеличивается в на 50% capacity от существующего. Это сделано потому, что не рационально каждый раз выделять память и перекопировать элементы, проще просто дать доступ к уже выделенной памяти которая содержится в capacity(). Щас попытаюсь вам привести примерчик:

	vector<int> vec;

	for(int i=0;i<100;i++)
	{
		cout <<vec.size()<<' '<<vec.capacity()<<endl;
		vec.push_back(i);
	}

из примера видно, что capacity() увеличивается на 50%.

vector::pop_back()

Эта функция удаляет последний элемент вектора.

	vector<int> vec(100);

	for(int i=0;vec.size()!=0;i++)
	{
		cout <<"vec.size()= "<<vec.size()<<endl;
		vec.pop_back();
	}

 

vector::insert()

Эта функция добавляет элементы в вектор. Щас рассмотрим ее возможности, я честно говоря призабыл. В общем я разобрался вот код с примером использования:

	//вектор из 4 элементов по 100
	vector<int> vec(4,100);

	//пытаемся добавить элементы через итератор
	vector<int>::iterator it=vec.begin();
	//вставляет 200 на место первого итератора
	//и возвращает итератор туда куда добавили элемент
	//в it указывает на элемент который добавили
	//то есть на первый элемент.
	it=vec.insert(it,200);
	//пытаемся вставить несколько элементов
	//например 3 с значением 300
	//в даном случае мы видим, 
	//что итератор не возвращается
	vec.insert(it,3,300);
	//выведем результаты
	for(int i=0;i<vec.size();i++)
		cout <<vec[i]<<' ';
	cout <<endl;
	//теперь попробуем вставить элементы 
	//в вектор через итераторы
	vector<int> vec1(3,500);//3 по 500
	vec.insert(vec.begin(),vec1.begin(),vec1.end());
	//проверим как добавились элементы
	for(int i=0;i<vec.size();i++)
		cout <<vec[i]<<' ';
	cout <<endl;
	//теперь добавим элементы из массива
	int mass[3]={1,2,3};
	vec.insert(vec.begin()+3,mass,mass+3);
	//выводим элементы
	for(int i=0;i<vec.size();i++)
		cout <<vec[i]<<' ';
	cout <<endl;

Тут существует одно правило, если мы вставляем один элемент в список то функция insert() возвращает итератор, а если мы вставляем целый список элементов, то конечно у нас итератор не возвращается. В общем как то отак все происходит.

vector::erase()

Слово переводится как стирать. То есть эта функция для удаления. Я ее тоже не сильно знаю, но щас все не ясное станет ясным. Разберемся.

От пример кода:

	vector<int> vec(10);

	for(int i=0;i<vec.size();i++)
	{
		vec[i]=i;
		cout <<vec[i]<<' ';
	}
	cout <<endl;

	//седьмой элемент
	vector<int>::iterator it=vec.begin();
	//возвращается итератор на следующий элемент за 
	//удаленным
	cout <<"*it+7= "<<*it+7<<endl;
	it=vec.erase(it+7);
	cout <<"*it= "<<*it<<endl;
	//удаление списка элементов
	//удалим 3 первых элемента из вектора
	vec.erase(vec.begin(),vec.begin()+3);
	for(int i=0;i<vec.size();i++)
		cout <<vec[i]<<' ';
	cout <<endl;

Я думаю все ясно стало. Простое удаление элементов по указателю.

vector::swap()

Я честно эту функцию не сильно знаю и что она принимает вроде указатели на элементы вектора и просто обменивает их местами. Щас попробую протестировать не ошибся ли я.

Да все таки я ошибся эта функция оказывается просто меняет два вектора. От пример ее использования:

	vector<int> vec(3,300);
	vector<int> vec1(5,200);
	//обмен векторов
	vec.swap(vec1);

	cout <<"vec= ";
	for(int i=0;i<vec.size();i++)
		cout <<vec[i]<<' ';
	cout <<endl;

	cout <<"vec1= ";
	for(int i=0;i<vec1.size();i++)
		cout <<vec1[i]<<' ';
	cout <<endl;

 

vector::clear()

Переводится как очистить. Ну эта функция просто полностью удаляет все элементы из вектора.

	vector<int> vec(3,300);
	cout <<"vec.size()= "<<vec.size()<<endl;//3
	//удаляем все элементы из вектора
	vec.clear();
	cout <<"vec.size()= "<<vec.size()<<endl;//0

 

vector::emplace()

Это новая функция стандарта 2011 года, я даже не знаю, для чего она нужна. Так пытался я только, что разобрать пример, но он увы у меня не запустился и не заработал. Значит пропустим его. Оставим на будущее 🙂 .

vector::emplace_back()

Тоже та же фишка новая фигня из стандарта 2011 года, тоже щас попробую проверить мб тоже не заработает. Увы примерчик кода у меня снова заработал с ошибкой, ну что ж пропустим значит. Оставим на будущее.

vector::get_allocator()

Ну эта функция явно со старого стандарта 1998 года, я правда не знаю, что она делает, щас попробую разобраться. Попробовал я реализовать этот аллокатор в общем получилось создать не понятно что. Я так думаю эта фигня как то выделяет память вот пример кода что получился:

	vector<int> vec;
	int* p;

	cout <<"vec.size()= "<<vec.size()<<endl;//0
	//выделение памяти на 5 элементов
	p=vec.get_allocator().allocate(5);
	cout <<"vec.size()= "<<vec.size()<<endl;//0

	//выделение памяти для массива.
	for(int i=0;i<5;i++)
		vec.get_allocator().construct(&p[i],i);
	cout <<"vec.size()= "<<vec.size()<<endl;//0

	//выведем содержимое массива.
	for(int i=0;i<5;i++)
		cout <<p[i]<<' ';
	cout <<endl;

	//уничтожение выделеной памяти

	for(int i=0;i<5;i++)
		vec.get_allocator().destroy(&p[i]);
	//удаление памяти на 5 элементов
	vec.get_allocator().deallocate(p,5);//наверняка удаляет память

 

relational operators

Переводится как операторы отношений. Щас попробуем составить пример с использованием этих операторов.

	vector<int> vec(3,200);
	vector<int> vec1(2,100);

	if(vec==vec1) cout <<"if vec == vec1"<<endl;
	else cout <<"vec != vec1"<<endl;
	if(vec!=vec1) cout <<"if vec != vec1"<<endl;

	if(vec>vec1) cout <<"if vec > vec1"<<endl;
	else cout <<"vec < vec1"<<endl;

	if(vec<vec1) cout <<"if vec < vec1"<<endl;
	else cout <<"vec > vec1"<<endl;

	if(vec>=vec1) cout <<"if vec >= vec1"<<endl;
	else cout <<"vec <= vec1"<<endl;

	if(vec<=vec1) cout <<"if vec <= vec1"<<endl;
	else cout <<"vec >= vec1"<<endl;

	return 0;

 

 utility::swap()

Эта swap() это внешняя функция, которая не находится в классе vector. Я думаю уже отета функция обменивает элементы вектора по итератору, а не сами векторы как предыдущая swap(), которая находится в классе vector.

        vector<int> vec(5);

	//вывод исходного вектора
	for(int i=0;i<vec.size();i++)
	{
		vec[i]=i;
		cout <<vec[i]<<' ';
	}
	cout <<endl;

	//обмениваем местами элементы первый и последний
	swap(vec[0],vec[4]);

	//вывод элементов
	for(int i=0;i<vec.size();i++)
		cout <<vec[i]<<' ';
	cout <<endl;

Ну и все пожалуй мы вроде все рассмотрели. Конечно мы не все рассмотрели, мне просто жаль, что мы не рассмотрели новые 3 метода из стандарта 2011 года, ну да ладно успеется. 🙂

rss