Standard Library Containers

std::vector

Dynamic array class template, which is declared in the corresponding header file from the standard library, provides its own memory management. In contrast to C-style arrays or fixed-size standard arrays, which need to know the size of the array at compile time, a vector can resize itself dynamically as elements are inserted or removed. It keeps its elements in contiguous memory positions. Thus, elements can be addressed by offsetting and the collection is very cache-friendly.

#include <iostream>
#include <vector>

int main() {
    // Initialize a vector of integers with four elements
    std::vector<int> numbers{ 10, 20, 30, 40 };

    // Iterate and print the elements
    for (int num : numbers) {
        std::cout << num << " ";
    }
    std::cout << "\n";

    return 0;
}

In order to access elements stored in a vector you can use either the subscript operator or the bounds-checked member function. Subscript operator doesn't check the validity of index passed to it. So it is fast but unsafe because if an invalid index is used then it leads to undefined behavior. Bounds-checked function checks the validity of the index against the range of the vector. If the index is invalid then the out-of-range exception is thrown and it prevents unauthorized memory access and catches some bugs during run-time.

#include <iostream>
#include <vector>

int main()
{
    std::vector<int> items{ 100, 200, 300 };

    // Fast access without bounds checking
    std::cout << "First item: " << items[0] << "\n";

    // Bounds-checked access with a valid index
    std::cout << "Third item: " << items.at(2) << "\n";

    return 0;
}
Vector stores its elements in one single contiguous memory allocation. It allows to have constant-time indexing and makes a nonempty vector data to be used with APIs that take a pointer and element count. Contiguous storage also works nicely with processor caches when code iterates over elements sequentially. Elements can be appended to a vector by the vector's append member function, which inserts a copy/move of the element to the vector's internal storage. Removal of the last element is performed by the vector's removal member function. Size function returns the number of elements currently stored in a vector. Emptiness-checking function returns a boolean value, which says whether a vector has zero elements. Clearing function removes all elements from a vector at once.
#include <iostream>
#include <vector>

int main() {
    std::vector<int> values;

    // Add elements dynamically
    values.push_back(5);
    values.push_back(10);
    values.push_back(15);

    std::cout << "Size after pushes: " << values.size() << "\n";

    // Remove the last element
    values.pop_back();

    std::cout << "Size after pop: " << values.size() << "\n";

    // Clear all elements
    values.clear();
    if (values.empty()) {
        std::cout << "Vector is now empty\n";
    }

    return 0;
}

In order to allocate memory efficiently vector differentiates between two parameters – its size and its capacity. Size is the number of elements stored in a vector. Capacity is the total number of elements that can be stored in the vector's currently allocated memory block without reallocation of a larger memory block. If you add an element and it exceeds the capacity, the vector performs the following steps – allocates a larger block of memory, moves/copies existing elements to the new location, destroys existing elements and deallocates the previous memory block.

Append is an amortized constant time operation rather than constant time operation. Most insertions at the beginning or in the middle require shifting of subsequent elements and insertion may lead to allocation of a larger memory block. Use bounds-checked access function if the checked access is beneficial and the subscript operator if the index is valid. Neither function makes an invalid index to be meaningful.
#include <iostream>
#include <vector>

int main() {
    std::vector<int> list;

    for (int i = 0; i < 5; ++i) {
        list.push_back(i);
        std::cout << "Size: " << list.size() 
                  << ", Capacity: " << list.capacity() << "\n";
    }

    return 0;
}
Since allocation of the new heap memory and moving elements during reallocation is an expensive operation you can optimize your program using reservation member function. If you know the number of elements the vector will hold you can allocate a specified number of memory in advance using this function. It guarantees that the vector will not need any reallocations when adding elements, until the reserved limit. Remember that the reserved memory changes capacity of the vector but not its size and initializes no elements.
#include <iostream>
#include <vector>

int main() {
    std::vector<int> optimized_list;

    // Pre-allocate memory for 100 elements
    optimized_list.reserve(100);

    std::cout << "Size: " << optimized_list.size() 
              << ", Capacity: " << optimized_list.capacity() << "\n";

    // These pushes will not trigger any reallocations
    optimized_list.push_back(1);
    optimized_list.push_back(2);

    return 0;
}
Safety requirement when using vectors is to pay attention to pointer and reference invalidations. If vector reallocates its memory for storing new elements then the old memory block is deallocated. Any raw pointers, references, and iterators pointing to elements of the vector become dangling. Using a pointer or reference to a vector element after reallocation leads to undefined behavior. In order to avoid it you should not keep any long-lived pointers or references to elements of the vector, which is not finalized yet.
Exercise: std::vectorStarter code, hints and solutionOpenClose
Guided practiceBeginner · 10–15 min

Practice: std::vector

Work through the mission, reveal hints only when needed, and compare your result with the model solution.

Your challenge

Push 20 before the first size report. Predict the sizes after pushing, popping, and clearing, and identify which element pop_back removes.

Mission checklist

  1. Run the starter as a baseline, then predict the change requested in Your challenge.
  2. Make that change in your editor; use the lesson-specific hints if you need help.
  3. Compile and run your answer, then compare with the worked solution and explain the result.

Starter program

This is the working baseline, not the completed answer. Compile as C++20, then make the change described above.

#include <iostream>
#include <vector>

int main() {
    std::vector<int> values;

    // Add elements dynamically
    values.push_back(5);
    values.push_back(10);
    values.push_back(15);

    std::cout << "Size after pushes: " << values.size() << "\n";

    // Remove the last element
    values.pop_back();

    std::cout << "Size after pop: " << values.size() << "\n";

    // Clear all elements
    values.clear();
    if (values.empty()) {
        std::cout << "Vector is now empty\n";
    }

    return 0;
}

Hints

Hint 1

Each push_back adds one element at the end, while pop_back removes the last element. Follow the size through those operations before clear runs.

Hint 2

Insert another push_back before the first size output and update both size predictions. clear removes all elements; empty then reports whether size is zero.

Worked solution

push_back(20) adds a fourth element. The first size becomes 4, pop_back removes that last element and leaves size 3, and clear still empties the vector.

#include <iostream>
#include <vector>

int main() {
    std::vector<int> values;

    // Add elements dynamically
    values.push_back(5);
    values.push_back(10);
    values.push_back(15);
    values.push_back(20);

    std::cout << "Size after pushes: " << values.size() << "\n";

    // Remove the last element
    values.pop_back();

    std::cout << "Size after pop: " << values.size() << "\n";

    // Clear all elements
    values.clear();
    if (values.empty()) {
        std::cout << "Vector is now empty\n";
    }

    return 0;
}

Example output

Size after pushes: 4
Size after pop: 3
Vector is now empty

0 comments

No comments yet. Be the first.

Add a comment

About CppLearn

CppLearn is an interactive, free reference for modern C++. In each lesson, you'll find out how the language works, rather than just lines of code that you can copy and paste. We cover concepts starting from beginner lessons on fundamentals and proceed to templates, move semantics, smart pointers, and areas that usually trap or scare C++ learners.