Vector is a sequence container that represents a dynamically resizable array. It provides contiguous storage for elements, allowing random access similar to arrays while automatically managing its size. Vectors are implemented using dynamic arrays that can grow or shrink as needed.
When new elements are inserted, vectors may need to reallocate memory. This involves allocating a new array and copying all existing elements to the new location. While this is an expensive operation, vectors optimize this by not reallocating on every insertion, making them efficient for most use cases.
Vector Usage and Key Interfaces
Vectors offer numerous interfaces for various operations. Below are the essential ones to master:
Vector Definition
| Constructor Declaration | Interface Description |
|---|---|
| vector() | Default constructor |
| vector(size_type n, const value_type& val = value_type()) | Constructs with n elements initialized to val |
| vector(const vector& x) | Copy constructor |
| vector(InputIterator first, InputIterator last) | Constructs from iterators |
Vector Iterator Usage
| Iterator Usage | Interface Description |
|---|---|
| begin() + end() | Returns iterator to first element / past-last element |
| rbegin() + rend() | Returns reverse iterator to last element / before-first element |
// Vector iterator example void displayVector(const std::vector& container) { // Using const iterator for read-only traversal std::vector::const_iterator pos = container.begin(); while (pos != container.end()) { std::cout << *pos << " "; ++pos; } std::cout << std::endl; }
</div>### Vector Space Growth
| Capacity Operations | Interface Description |
|---|---|
| size() | Returns number of elements |
| capacity() | Returns current capacity |
| empty() | Checks if vector is empty |
| resize() | Changes vector size |
| reserve() | Changes vector capacity |
Note that capacity growth factors differ between implementations: Visual Studio uses 1.5x growth, while GCC uses 2x growth. The reserve() function only allocates space without affecting size, which can optimize performance when the required capacity is known in advance.
### Vector CRUD Operations
| Vector Operations | Interface Description |
|---|---|
| push\_back() | Adds element at end |
| pop\_back() | Removes last element |
| find() | Searches for element (algorithm, not member) |
| insert() | Inserts before specified position |
| erase() | Removes element at poistion |
| swap() | Exchanges contents with another vector |
| operator\[\] | Random access like array |
### Vector Iterator Invalidation
Iterators provide an abstraction that allows algorithms to work with different data structures. In vectors, iterators are essentially raw pointers (T\*). Iterator invalidation occurs when the underlying memory is deallocated, leading to undefined behavior if the invalidated iterator is used.
Operations that may invalidate vector iterators include:
#### 1. Operations that modify storage capacity
<div>```
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
std::vector<int> data{10, 20, 30, 40, 50, 60};
auto position = data.begin();
// Operations that may reallocate memory:
// data.resize(100, 0); // Changes size and possibly capacity
// data.reserve(200); // Changes capacity
// data.insert(data.begin(), 0); // May reallocate
// data.push_back(70); // May reallocate
// data.assign(100, 0); // Replaces content, may reallocate
/*
Problem: These operations might deallocate the original memory,
leaving the iterator pointing to invalid memory. Using it afterward
can cause crashes or undefined behavior.
Solution: Reassign the iterator after such operations.
*/
while (position != data.end())
{
std::cout << *position << " ";
++position;
}
std::cout << std::endl;
return 0;
}
</int></algorithm></vector></iostream>
#include #include #include
int main() { int values[] = {5, 10, 15, 20}; std::vector collection(values, values + sizeof(values)/sizeof(int));
// Find element 15
auto location = std::find(collection.begin(), collection.end(), 15);
// Delete element at found position
collection.erase(location);
// This may cause undefined behavior:
std::cout << *location << std::endl; // Potential invalid access
return 0;
}
</div>When erase() removes an element, subsequent elements shift forward. While this doesn't change the underlying storage, the iterator becomes invalid if it pointed to the last element (which becomes end() after deletion).
**Solution for iterator invalidation:** Always reassign iterators after operations that might invalidate them.
</div>