Vectors in C++

std::vector is one of the most commonly used containers in C++ because it provides a dynamic array that can grow and shrink as needed. Here's a detailed explanation of the various functions and operations associated with std::vector:

1. Creating a Vector

std::vector<int> vec; // Creates an empty vector of integers
std::vector<int> vec(5); // Creates a vector of size 5 with default-initialized elements (0 for int)
std::vector<int> vec(5, 10); // Creates a vector of size 5 with all elements initialized to 10
std::vector<int> vec = {1, 2, 3, 4, 5}; // Creates and initializes a vector using an initializer list

2. Accessing Elements

  • operator[]: Accesses the element at the specified index. No bounds checking.

  • at(): Accesses the element at the specified index with bounds checking.

  • front(): Returns a reference to the first element.

  • back(): Returns a reference to the last element.

std::vector<int> vec = {1, 2, 3};
int a = vec[1]; // a = 2
int b = vec.at(1); // b = 2
int first = vec.front(); // first = 1
int last = vec.back(); // last = 3

3. Modifying the Vector

  • push_back(): Adds an element to the end of the vector.

  • pop_back(): Removes the last element from the vector.

  • insert(): Inserts elements at a specified position.

  • erase(): Removes elements from a specified position or range.

  • clear(): Removes all elements from the vector.

  • resize(): Resizes the vector to the specified size.

  • assign(): Assigns new values to the vector.

std::vector<int> vec = {1, 2, 3};
vec.push_back(4); // vec becomes {1, 2, 3, 4}
vec.pop_back(); // vec becomes {1, 2, 3}

vec.insert(vec.begin() + 1, 5); // vec becomes {1, 5, 2, 3}
vec.erase(vec.begin() + 1); // vec becomes {1, 2, 3}

vec.resize(5, 10); // vec becomes {1, 2, 3, 10, 10}
vec.clear(); // vec becomes empty

vec.assign(3, 7); // vec becomes {7, 7, 7}

4. Size and Capacity

  • size(): Returns the number of elements in the vector.

  • capacity(): Returns the number of elements that the vector can hold before needing to allocate more memory.

  • empty(): Checks whether the vector is empty.

  • reserve(): Requests that the vector capacity be at least enough to contain a specified number of elements.

  • shrink_to_fit(): Reduces the capacity of the vector to fit its size.

std::vector<int> vec = {1, 2, 3};
size_t sz = vec.size(); // sz = 3
size_t cap = vec.capacity(); // cap >= 3

bool isEmpty = vec.empty(); // isEmpty = false

vec.reserve(10); // vec's capacity becomes at least 10
vec.shrink_to_fit(); // reduces the capacity to size

5. Iterators

  • begin(): Returns an iterator to the first element.

  • end(): Returns an iterator to the element following the last element.

  • rbegin(): Returns a reverse iterator to the last element.

  • rend(): Returns a reverse iterator to the element preceding the first element.

std::vector<int> vec = {1, 2, 3};
for (auto it = vec.begin(); it != vec.end(); ++it) {
    std::cout << *it << " "; // Output: 1 2 3
}

for (auto it = vec.rbegin(); it != vec.rend(); ++it) {
    std::cout << *it << " "; // Output: 3 2 1
}

6. Swapping

  • swap(): Exchanges the contents of two vectors.
std::vector<int> vec1 = {1, 2};
std::vector<int> vec2 = {3, 4};
vec1.swap(vec2); // vec1 becomes {3, 4}, vec2 becomes {1, 2}

7. Comparison Operators

  • ==, !=, <, <=, >, >=: These operators compare two vectors lexicographically.
std::vector<int> vec1 = {1, 2, 3};
std::vector<int> vec2 = {1, 2, 4};

bool isEqual = (vec1 == vec2); // isEqual = false
bool isLess = (vec1 < vec2); // isLess = true (because 3 < 4)

8. Data Access

  • data(): Returns a direct pointer to the memory array used internally by the vector.
std::vector<int> vec = {1, 2, 3};
int* p = vec.data();
std::cout << p[0] << " " << p[1] << " " << p[2]; // Output: 1 2 3

9. Emplace Functions

  • emplace_back(): Constructs and inserts an element at the end of the vector.

  • emplace(): Constructs and inserts an element at the specified position.

std::vector<std::pair<int, int>> vec;
vec.emplace_back(1, 2); // vec contains {(1, 2)}

std::vector<int> vec2 = {1, 3};
vec2.emplace(vec2.begin() + 1, 2); // vec2 becomes {1, 2, 3}

10. Copying and Moving Vectors

  • Copy Constructor: Creates a new vector as a copy of an existing one.

  • Move Constructor: Transfers the contents of one vector to another without copying.

std::vector<int> vec1 = {1, 2, 3};
std::vector<int> vec2 = vec1; // Copy constructor
std::vector<int> vec3 = std::move(vec1); // Move constructor (vec1 is now empty)

11. Non-Member Functions

  • std::swap(): Swaps the contents of two vectors.

  • std::begin(), std::end(): Returns iterators to the beginning and end of the vector, respectively.

std::vector<int> vec1 = {1, 2};
std::vector<int> vec2 = {3, 4};
std::swap(vec1, vec2); // vec1 becomes {3, 4}, vec2 becomes {1, 2}

for (auto it = std::begin(vec1); it != std::end(vec1); ++it) {
    std::cout << *it << " "; // Output: 3 4
}

12. Capacity Functions

  • max_size(): Returns the maximum number of elements the vector can hold.
std::vector<int> vec;
size_t maxSize = vec.max_size(); // Returns the maximum possible size of the vector

Summary

std::vector is extremely versatile and can handle a wide range of use cases with its rich set of functions. Understanding these functions and how to use them efficiently can make a big difference in the performance and readability of your code, especially in competitive programming where time is of the essence.

Did you find this article valuable?

Support Sarthak by becoming a sponsor. Any amount is appreciated!