Introduction to C++ container vector and its use

1 Introduction to vector

  • vector is a serialized container for variable-size arrays
  • Just like arrays, vectors also use contiguous storage space to store elements. This means that you can use subscripts to access the elements of a vector, which is as efficient as an array. But unlike an array, its size can be changed dynamically, and its size will be automatically processed by the container.
  • Essentially, vector uses a dynamically allocated array to store its elements. When new elements are inserted, the array needs to be re-allocated. In order to increase storage space. The method is to allocate a new array, and then move all the elements to this array. In terms of time, this is a relatively expensive task, because every time a new element is added to the container, the vector does not reallocate its size every time.
  • Vector allocation strategy: vector will allocate some additional space to accommodate possible growth, because the storage space is larger than the actual storage space needed. Different libraries adopt different strategies to balance the use and reallocation of space. But in any case, the redistribution should be a logarithmic increase of the interval size, so that when an element is inserted at the end, it is done in constant time complexity.
  • Therefore, vector occupies more storage space, in order to obtain the ability to manage storage space, and dynamically grow in an effective way.
  • Compared with other dynamic sequence containers (deques, lists and forward_lists), vector is more efficient when accessing elements, and adding and deleting elements at the end is relatively efficient. For other delete and insert operations that are not at the end, the efficiency is lower. It is better than the unified iterator and reference of lists and forward_lists.

2 Use of vector

2.1 Constructor of vector

Insert picture description here

#include <vector>
#include <iostream>

using namespace std;
int main()
{
    
    
	vector<int> v0; 
	vector<int> v1(10, 3);
	vector<int> v2(v1);
	vector<int> v3(v2.begin(), v2.end());
	return 0;
}

2.2 Traversal of vector

Use [] to traverse

vector<int> v0; 
	vector<int> v1(10, 3);
	vector<int> v2(v1);
	vector<int> v3(v2.begin(), v2.end());
	for (int i = 0; i < v2.size(); i++)
	{
    
    
		cout << v2[i]<< " ";
	}
	cout << endl;

Iterator traversal
Insert picture description here
Insert picture description here

    vector<int> v0; 
	vector<int> v1(10, 3);
	vector<int> v2(v1);
	vector<int> v3(v2.begin(), v2.end());
	vector<int>::iterator it = v3.begin();
	while (it != v3.end())
	{
    
    
		cout << *it << " ";
		++it;
	}
	cout << endl;

Range for traversal, the underlying implementation of range for is iterator

    vector<int> v0; 
	vector<int> v1(10, 3);
	vector<int> v2(v1);
	vector<int> v3(v2.begin(), v2.end());
	vector<int>::iterator it = v3.begin();
	for (const auto& e : v3)
	{
    
    
		cout << e << " ";
	}
	cout << endl;

2.3 Space growth problem of vector

Here is a focus on resize and reserve,
see the code below

#include <iostream>
#include <vector>
int main()
{
    
    
	size_t sz;
	std::vector<int> foo;
	sz = foo.capacity();
	std::cout << "making foo grow:\n";
	for (int i = 0; i < 100; ++i) {
    
    
		foo.push_back(i);
		if (sz != foo.capacity()) {
    
    
			sz = foo.capacity();
			std::cout << "capacity changed: " << sz << '\n';
		}
	}
	return 0;
}

Compile and run the executable program under VS and g++ respectively under VS
: Under
Insert picture description here
g++:
Insert picture description here

  • The capacity code is run separately in vs and g++, and you will find that cpacity under vs is increased by 1.5 times, and g++ is increased by 2 times.
  • Reserve is only responsible for opening up space. If you know how much space is needed, reserve can alleviate the cost of vector expansion. It will be reflected in the following code.
  • When resize opens up space, it also initializes and changes the size.

** Use reserve to open up space in advance to reduce the overhead caused by capacity expansion**

#include <iostream>
#include <vector>
int main()
{
    
    
	size_t sz;
	std::vector<int> foo;
	
	foo.reserve(123);
	sz = foo.capacity();
	std::cout << "making foo grow:\n";
	for (int i = 0; i < 100; ++i) {
    
    
		foo.push_back(i);
		if (sz != foo.capacity()) {
    
    
			sz = foo.capacity();
			std::cout << "capacity changed: " << sz << '\n';
		}
	}
	return 0;
}

Usage of resize

#include <iostream>
#include <vector>

using std::cout;
using std::endl;
int main()
{
    
    
	std::vector<int> myvector;

	for (int i = 1; i < 10; i++)
		myvector.push_back(i);

	myvector.resize(5);
	myvector.resize(8, 100);
	myvector.resize(12);

	std::cout << "myvector contains:";
	for (const auto& e : myvector)
	{
    
    
		cout << e << ' ';
	}
	cout << '\n';
	return 0;
}

Insert picture description here
Let’s search for the resize function!

2.4 Adding, deleting, checking and modifying vector

Insert picture description here
Usage of push_back / pop_back

#include <iostream>
#include <vector>

using std::cout;
using std::endl;

int main()
{
    
    
	int a[] = {
    
     1, 2, 3, 4 };
	std::vector<int> v(a, a + sizeof(a) / sizeof(int));//用迭代器来构造

	std::vector<int>::iterator it = v.begin();
	while (it != v.end())
	{
    
    
		cout << *it << " ";
		++it;
	}
	cout << endl;
	v.pop_back();
	v.pop_back();

	it = v.begin();//注意要重新赋值,要不迭代器会失效

	while (it != v.end())
	{
    
    
		cout << *it << " ";
		++it;
	}
	cout << endl;

	return 0;
}

The usage of find / insert / erase

#include <iostream>
#include <vector>

using std::cout;
using std::endl;

int main()
{
    
    
	int a[] = {
    
     1, 2, 3, 4,5,6,7 };
	std::vector<int> v(a, a + sizeof(a) / sizeof(int));//用迭代器来构造

	// 使用 find 查找 3 所在位置的迭代器 iterator
	std::vector<int>::iterator pos = find(v.begin(), v.end(), 3);
	if (pos != v.end())
	{
    
    
		cout << "found!" << endl;
		*pos = 23;
	}
	//在 pos 位置出插入30

	v.insert(pos, 34);

	std::vector<int>::iterator it = v.begin();
	while (it != v.end())
	{
    
    
		cout << *it << " ";
		++it;
	}
	//删除34位置处的数据
	cout << endl;
	pos = find(v.begin(), v.end(), 34);
	v.erase(pos);

	it = v.begin();
	while (it != v.end())
	{
    
    
		cout << *it << " ";
		++it;
	}
	cout << endl;
	return 0;
}

Insert picture description here

3 Vector's iterator failure problem

The main role of iterator is to allow the algorithm can not care about the underlying data structure, the underlying is actually a pointer , or a pointer is a package , such as: vector iterator is the original ecology pointer T *. Therefore, the iterator is invalid, in fact, the
space pointed to by the corresponding pointer at the bottom of the iterator is destroyed, and the use of a free space will cause the program to crash (that is, if you continue to use the invalidated iterator, the program may crash ).

  • Operations that will cause changes in the underlying space may be the iterator failure, such as: resize, reserve, insert, assign,
    push_back, etc.
  • Delete operation of the specified position element-erase
void test01()
{
    
    
	vector<int> myvec = {
    
     1, 2, 3, 5 };
	auto it = myvec.begin();
	while (it != myvec.end())
	{
    
    
		if ((*it & 1) == 0)//判断是否为偶数
		{
    
    
			 myvec.erase(it);
		}
		++it;
	}
}
void test02()
{
    
    
	vector<int> myvec = {
    
     1, 2, 3, 5 };
	auto it = myvec.begin();
	while (it != myvec.end())
	{
    
    
		if ((*it & 1) == 0)//判断是否为偶数
		{
    
    
			it = myvec.erase(it);
		}
		else
		{
    
    
			++it;
		}
	}
}

Call test01
Insert picture description here
call test02
Insert picture description here

After erase deletes the element at the pos position, the element after the pos position will move forward without causing a change in the underlying space. Theoretically speaking, the iterator should not be invalid, but: if pos happens to be the last element, pos happens to be after deletion The end position, and the end position has no elements, then pos is invalid. Therefore, when deleting an element at any position in the vector, vs. considers that the position iterator is invalid.

Solution:
Iterator is invalid. Solution: Before using, just re-assign the iterator.
In the following article, we will discuss the underlying implementation of vector and explore the subtleties of STL

Guess you like

Origin blog.csdn.net/CZHLNN/article/details/115350549