This article has been included in the “C++ Language and Advanced Data Structures” column!
Author: ARMCSKGT
Use of vector in STL
- foreword
- text
-
- default member function
-
- common structure
- copy construction
- destructor
- assignment overloading
- iterator
-
- forward iterator
- reverse iterator
- const iterator
- capacity class
-
- Space capacity query
- Space Capacity Operations
-
- Expansion operation
- Number of Elements Operations
- Shrink operation
- data access
-
- subscript access
- Head and tail element access
- get raw pointer
- Element insertion and deletion operations
-
- Tail plug and tail delete
- Insert and delete at any position
- insert anywhere
- delete anywhere
- Other operation functions
-
- exchange function
- clear function
- at last
Foreword
vector is a variable-sized array sequence container, generally also called a vector; the underlying principle is a sequence table, but vector is a generic container that can support storage of int, double and even custom types, and is frequently and widely used in normal times , vector can improve our development efficiency in many scenarios, so it is necessary to learn how to use vector as a powerful tool!
Text
This article will introduce the common interface of vector, according to the official document of C++ vector!
First, before using vector, you need to declare the header file < vector > and declare the namespace std!
Vector is a generic container through a template instance, which needs to be instantiated by specifying the type!
Default member function
There are three conventional constructions for vector, but in C++11, a useful construction method has been added!
Common structure
vector supports the following constructs:
- Default construction (generates an empty container object without any data)
- Construct n objects whose elements are val
- iterator range construction
- List initialization construction
#include <iostream> #include <vector> using namespace std; int main() {<!-- --> vector<int> v1; //Default construction vector<int> v2(5, 10); //Construct 5 objects with 10 elements int arr[] = {<!-- --> 1,2,3,4,5 }; vector<int> v3(arr, arr + (sizeof(arr) / sizeof(arr[0]))); //iterator interval construction vector<int> v4 = {<!-- --> 6,7,8,9,10 }; //List initialization construction return 0; }Copy construction
When we define an object, we can let the new object copy an existing object to complete the initialization!
#include <iostream> #include <vector> using namespace std; int main() {<!-- --> vector<int> v1(10, 1); //Two copy construction methods vector<int> v2(v1); vector<int> v3 = v1; return 0; }Destructor
The destructor is automatically called at the end of the vector object’s life cycle, and we don’t need to care about the use phase!
Assignment overload
vector supports assignment to copy an object (provided that the object already exists and not constructed), and C++11 supports assignment through list initialization!
#include <iostream> #include <vector> using namespace std; int main() {<!-- --> vector<int> v1 = {<!-- -->1,2,3}; vector<int> v2; v2 = v1; //Assign empty object vector<int> v3 = {<!-- --> 4,5,6 }; v3 = {<!-- -->10,11,12}; //Assign objects with existing data through the list return 0; }
It can be found that when there is data in the object, the assignment to it will reflect the original data, and the vector object can also be initialized through the list!
Iterator
- vector supports two kinds of iterators forward and reverse (C++ 11), both of which have const versions!
- The iterator is to encapsulate the pointer and construct it into an iterator object, and control the operable behavior by yourself!
- The iterator of vector is a random iterator, which can ± any integer to any element while supporting ++ and – -, so sort can be used!
Forward iterator
Forward iterator traversal, the default is from begin() to end()!
begin points to the position of the first element in the vector, and end points to the next position of the last element!
You cannot use > and < etc. when judging the end condition, because after the iterator is encapsulated, you don’t know whether it is a continuous space, just judge whether it is equal to end!
#include <iostream> #include <vector> using namespace std; int main() {<!-- --> vector<int> v = {<!-- --> 1,2,3,4,5 }; vector<int>::iterator it = v.begin(); //Define vector<int>iterator type //auto it = v.begin(); //If you feel troublesome, you can also use auto while (it != v. end()) {<!-- --> cout << *it << " "; + + it; } cout << endl; return 0; }Reverse iterator
As the name suggests, the opposite of a forward iterator!
rend points to the previous position of the first element in the vector, and rbegin points to the position of the last element!
#include <iostream> #include <vector> using namespace std; int main() {<!-- --> vector<int> v = {<!-- --> 1,2,3,4,5 }; vector<int>::reverse_iterator rit = v.rbegin(); while (rit != v. rend()) {<!-- --> cout << *rit << " "; + + rit; } cout << endl; return 0; }
The ++ of the reverse iterator is to go from the back to the front, which is the opposite of the behavior of the forward iterator!const iterator
In some scenarios such as:
//vector object const reference parameter, the iterator declared in the function is a const iterator void Print(const vector<int> & v) {<!-- -->} // When the range for uses const to modify the element, the bottom layer calls the const iterator for (const auto & x : v) {<!-- -->}Usually we rarely use const iterators, but we can also actively define them!
vector<int>::const_iterator //const forward iterator vector<int>::const_reverse_iterator ///const reverse iteratorA const iterator cannot modify the element pointed to by the iterator, but it can change the point of the iterator!
Capacity class
Operations on capacity query and modification:
Space capacity query
Vector supports the following capacity query operations:
- Query the number of elements size
- Query the current capacity capacity
- Query whether the current object is empty (no element exists) empty
- The query object can hold the maximum number of elements (estimated, not exact) max_size
#include <iostream> #include <vector> using namespace std; int main() {<!-- --> vector<int> v = {<!-- --> 1,2,3 }; cout << "size:" << v. size() << endl; cout << "capacity:" << v. capacity() << endl; cout << "empty:" << (bool)v.empty() << endl; cout << "max_size:" << v.max_size() << endl; return 0; }
The max_size will change due to factors such as different instance types and different platforms!
Space capacity operation
Expansion operation
Vector supports manual capacity expansion using the reserve function. In some scenarios where the number of elements is known, space can be opened up in advance to improve performance and reduce memory fragmentation!
First, let’s take a look at vector’s own expansion mechanism:
VS platform (PJ version)
g++ platform (SGI version)
Through observation, we found that the expansion under VS is 1.5 times, and the expansion under g++ is 2 times; these two expansion strategies have their own advantages and disadvantages. When the amount of data is relatively large, frequent expansion of VS will lead to performance degradation; when the amount of data At medium, g++ expands redundancy too much and wastes space!In response to this situation, we can use reserve to expand capacity in advance to avoid these two situations!
vector<int> v; v.reverse(n); //Expand the capacity to n in advanceExample:
#include <iostream> #include <vector> using namespace std; int main() {<!-- --> vector<int> v; v. reserve(100); cout << "capacity:" << v. capacity() << endl; v.reserve(50); //reserve does not support shrinkage cout << "capacity:" << v. capacity() << endl; return 0; }
Number of elements operation
Vector supports the use of the resize function to customize the number of elements. If the number we set is greater than the current capacity, it will trigger expansion!
#include <iostream> #include <vector> using namespace std; int main() {<!-- --> vector<int> v = {<!-- -->1,2,3}; cout << "size:" << v. size() << endl; cout << "capacity:" << v. capacity() << endl; \t v. resize(50); cout << "size:" << v. size() << endl; cout << "capacity:" << v. capacity() << endl; v. resize(10); cout << "size:" << v. size() << endl; cout << "capacity:" << v. capacity() << endl; return 0; }
Obviously, resize changes the size of the size, no matter what, it will not shrink!
If in resize(n), n is greater than the current size, the newly increased space will be initialized with the default construction of the instantiated type!
In order to be compatible with custom types, built-in types also support initialization and construction like defining objects, which is to construct through int(), just like anonymous objects, except that int() is equivalent to 0!int main() {<!-- --> int a(1); //object initialization method int b = int(2); //Anonymous object copy construction method cout << a << endl; cout << b << endl; return 0; }Of course resize also supports the specified value to initialize the growth space
#include <iostream> #include <vector> using namespace std; int main() {<!-- --> vector<int> v = {<!-- -->1,2,3}; v.resize(10,668); //Specify to initialize the new element space as 668 return 0; }
Equivalent to reserve, resize can not only expand capacity, but also complete initialization. Both have their own application scenarios!Scale down operation
C++11 provides shrinking operations for containers. The shrink_to_fit function is rarely used in normal times, because it consumes a lot of performance!
vector<int> v(100,1); v.shrink_to_fit(10); //Reduce the capacity to 10The underlying principle is probably to re-open up a space of appropriate size and transfer data according to the free space!
Data Access
Vector is a sequential table, and there are many ways to range it. In addition to the general iterator range, there are the following ways to access data:
Subscript access
The bottom layer of vector is a sequential table, so it must support subscript random access!
There are two ways to access subscripts. On the basis of native access through [], there is also an at() in the library that can also be accessed through subscripts. The difference between the two is:
- Access through [ ], if the subscript is out of bounds, error will be reported
- Access through at() will throw an exception if the subscript is out of bounds
#include <iostream> #include <vector> using namespace std; int main() {<!-- --> vector<int> v = {<!-- -->1,2,3}; for (int i = 0; i < v. size(); + + i) {<!-- --> printf("v[%d]=%d,v.at(%d)=%d\\ ",i, v[i], i, v.at(i)); } return 0; }Head and tail element access
Vector supports the reference or const reference of the head and tail elements, and it is rarely used at ordinary times, just understand it!
#include <iostream> #include <vector> using namespace std; int main() {<!-- --> vector<int> v = {<!-- --> 1,2,3 }; cout << v. front() << endl; cout << v.back() << endl; return 0; }Get native pointer
Vector supports obtaining the direct native space of storage elements through the data function!
Through this pointer, like accessing an array, use subscript access or * dereference to access and modify the elements of each space!
This is rarely used, and it is very dangerous, so it is not recommended to use it!#include <iostream> #include <vector> using namespace std; int main() {<!-- --> vector<int> v = {<!-- --> 1,2,3 }; int* p = v. data(); p[1] = 4; for (const auto & x : v) {<!-- --> cout << x << endl; } return 0; }
Element insertion and deletion operations
Vector has many operation functions for modifying elements, but we only need to understand the most commonly used ones!
Tail insertion and deletion
- The push_back(val) function can insert val into the end of the current vector container
- The pop_back() function can delete an element from the end of the current container
#include <iostream> #include <vector> using namespace std; void Print(const vector<int> & v) {<!-- --> for (const auto & x : v) {<!-- --> cout << x << " "; } cout << endl; } int main() {<!-- --> vector<int> v = {<!-- --> 4,5,6 }; v. pop_back(); Print(v); v. push_back(668); Print(v); return 0; }Insert and delete at any position
Insert anywhere
The insert function has three forms and supports:
- Insert a val element at the current iterator position (equivalent to inserting an element before an element) and return the iterator of the newly inserted element
– This return value is crucial! When we insert an element, expansion may be triggered, then the original iterator will become invalid (the iterator becomes invalid), and insert will return a new iterator pointing to the inserted element to facilitate subsequent operations!- Insert n elements val elements at the current iterator position, no return value
- Insert the iterator interval of any container at the current iterator position, no return value
– For these two functions, the iterator must be manually updated after insertion, otherwise the compiler will report an error!#include <iostream> #include <vector> using namespace std; void Print(const vector<int> & v) {<!-- --> for (const auto & x : v) {<!-- --> cout << x << " "; } cout << endl; } int main() {<!-- --> vector<int> v = {<!-- --> 4,5,6 }; v.insert(v.begin(), 1); //head insert 1 Print(v); v.insert(v.begin(), 2); //head insert 1 Print(v); v.insert(v.begin() + 2, 2, 668); //Insert two 668 before element 2 Print(v); int arr[] = {<!-- --> 9,6,3 }; v.insert(v.begin() + 1, arr, arr + (sizeof(arr) / sizeof(arr[0]))); // Insert an array before element 1 Print(v); return 0; }
Delete anywhere
There are two forms for erasing any position:
- Delete the element pointed by the current iterator, and return the element iterator after this element
- Delete an iterator range of the container, and return an iterator of the next element in the range
–The deletion operation will inevitably cause the iterator to become invalid, so each deletion operation will update the iterator!#include <iostream> #include <vector> using namespace std; void Print(const vector<int> & v) {<!-- --> for (const auto & x : v) {<!-- --> cout << x << " "; } cout << endl; } int main() {<!-- --> vector<int> v = {<!-- -->1,2,3,4,5,6,7,8,9,10}; Print(v); v.erase(v.begin()); //head delete Print(v); v.erase(v.begin() + 2, v.begin() + 7); //Delete elements 2-7 Print(v); return 0; }
Deletion consumes a lot of performance, because it involves moving data, and it is not used much at ordinary times!
Other operation functions
Exchange function
Vector has its own exchange function, and its bottom layer is the space managed by both sides of the exchange!
#include <iostream> #include <vector> using namespace std; void Print(const vector<int> & v) {<!-- --> for (const auto & x : v) {<!-- --> cout << x << " "; } cout << endl; } int main() {<!-- --> vector<int> v1 = {<!-- --> 1,2,3,4,5 }; vector<int> v2 = {<!-- --> 6,7,8,9,10 }; v1. swap(v2); Print(v1); Print(v2); return 0; }
Of course, vector also supports the unified swap function in the library, but it needs to declare the algorithm header file algorithm to use it!#include <iostream> #include <vector> #include <algorithm> //algorithm header file using namespace std; int main() {<!-- --> vector<int> v1 = {<!-- --> 1,2,3,4,5 }; vector<int> v2 = {<!-- --> 6,7,8,9,10 }; swap(v1,v2); return 0; }Empty function
The clear function can clear all the elements of the current vector object, but it will not shrink or destroy the object!
#include <iostream> #include <vector> using namespace std; void Print(const vector<int> & v) {<!-- --> for (const auto & x : v) {<!-- --> cout << x << " "; } cout << endl; } int main() {<!-- --> vector<int> v = {<!-- --> 1,2,3,4,5 }; cout << "size:" << v. size() << endl; cout << "capacity:" << v. capacity() << endl; v. clear(); cout << "size:" << v. size() << endl; cout << "capacity:" << v. capacity() << endl; return 0; }
Last
This is the end of the introduction to the use of vector. Vector is a powerful generic sequence table, which makes up for the shortcomings of arrays that cannot be dynamically expanded, and the generic idea allows vector to be instantiated into any type of sequence table, but In fact, there is only one code; later I will reveal the secrets of the bottom layer of vector for you, and introduce the bottom layer implementation of vector!
This time
If there are flaws in the article, please comment and leave a message carefully, and I will fix the mistakes immediately, thank you!
Other articles reading recommendation
C ++
?
?