How to Remove an Element from a Vector in C++

by | C++, Programming, Tips

In this guide, we’ll explore different techniques to remove elements from vectors in C++. We’ll cover both traditional and modern approaches, helping you choose the most appropriate method for your needs.

📚 Quick Reference: Vector Element Removal
pop_back()
A method to remove the last element from a vector with O(1) complexity, used for efficient back element removal.
erase()
A method to remove an element at a specific position or a range of elements, shifting subsequent elements left.
erase-remove Idiom
A common C++ pattern combining std::remove and erase to remove elements matching a condition.
std::erase / std::erase_if
Convenient C++20 methods for direct removal of elements by value or condition without using the erase-remove idiom.
std::unique
An algorithm to remove consecutive duplicates from a vector, used after sorting for removing all duplicates.
std::partition
An algorithm to rearrange elements into two groups based on a condition, with unwanted elements moved to the end.
Iterator Invalidation
A scenario where iterators become invalid after certain operations like erase, requiring careful handling in loops.
shrink_to_fit()
A method to reduce a vector’s capacity to fit its size, useful after removing many elements to optimize memory usage.

Basic Element Removal

Let’s start with the fundamental methods for removing elements from a vector.

Basic Vector Element Removal
#include <iostream>
#include <vector>

int main() {
    // Create a vector with some elements
    std::vector<int> numbers = {1, 2, 3, 4, 5};

    // Remove last element using pop_back()
    numbers.pop_back();

    // Remove element at specific index using erase()
    numbers.erase(numbers.begin() + 1);  // Removes second element

    // Print remaining elements
    std::cout << "After removal: ";
    for(const auto& num : numbers) {
        std::cout << num << " ";
    }
    std::cout << std::endl;

    return 0;
}
After removal: 1 3 4

Key Points:

  • pop_back(): Removes the last element (O(1) complexity)
  • erase(iterator): Removes element at specific position (O(n) complexity)
  • After erasure, all elements after the removed position are shifted left

Manual Iteration and Erasure

For more control over the removal process, you can manually iterate through the vector and use erase to remove elements that match a specific condition. This method is useful when complex logic is required for element removal.

Using Manual Iteration
#include <iostream>
#include <vector>

int main() {
    std::vector<int> numbers = {1, 2, 3, 2, 4, 2, 5};

    // Iterate through the vector and remove all occurrences of 2
    for (auto it = numbers.begin(); it != numbers.end(); ) {
        if (*it == 2) {
            it = numbers.erase(it);  // Remove element and update iterator
        } else {
            ++it;  // Increment iterator only if not erasing
        }
    }

    // Print remaining elements
    std::cout << "After manual removal of 2s: ";
    for (const auto& num : numbers) {
        std::cout << num << " ";
    }
    std::cout << std::endl;

    return 0;
}
After manual removal of 2s: 1 3 4 5

Key Points:

  • Carefully manage the iterator to avoid invalidation after erase.
  • This method is flexible for custom conditions but can be verbose compared to std::remove or std::partition.
  • Best suited for situations requiring detailed control over element removal.

The Erase-Remove Idiom

The erase-remove idiom is a powerful technique for removing elements that match specific criteria.

Erase-Remove Idiom Example
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> numbers = {1, 2, 3, 2, 4, 2, 5};

    // Remove all occurrences of 2
    numbers.erase(
        std::remove(numbers.begin(), numbers.end(), 2),
        numbers.end()
    );

    // Remove elements matching a condition
    auto isEven = [](int n) { return n % 2 == 0; };
    numbers.erase(
        std::remove_if(numbers.begin(), numbers.end(), isEven),
        numbers.end()
    );

    // Print remaining elements
    std::cout << "After removing 2s and even numbers: ";
    for(const auto& num : numbers) {
        std::cout << num << " ";
    }
    std::cout << std::endl;

    return 0;
}
After removing 2s and even numbers: 1 3 5

Removing All Elements: clear()

The clear() method is the simplest way to remove all elements from a vector. It efficiently empties the vector, leaving it with zero elements.

Using clear() with shrink_to_fit()
#include <iostream>
#include <vector>

int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5};

    // Clear all elements
    numbers.clear();

    // Reduce the capacity of the vector
    numbers.shrink_to_fit();

    // Check if the vector is empty and print its capacity
    if (numbers.empty()) {
        std::cout << "Vector is now empty!" << std::endl;
        std::cout << "Vector capacity after shrink_to_fit: " << numbers.capacity() << std::endl;
    }

    return 0;
}
Vector is now empty!
Vector capacity after shrink_to_fit: 0

Key Points:

  • clear() removes all elements from the vector.
  • The capacity of the vector remains unchanged; use shrink_to_fit() to release unused memory.

Removing Consecutive Duplicates: std::unique

The std::unique algorithm is used to remove consecutive duplicate elements from a sorted or unsorted vector. It shifts the unique elements to the beginning of the vector and returns an iterator pointing to the new end of the range with unique elements.

Using std::unique
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    // Create a vector with consecutive duplicates
    std::vector<int> numbers = {1, 1, 2, 2, 3, 4, 4, 5};

    // Remove consecutive duplicates
    auto newEnd = std::unique(numbers.begin(), numbers.end());

    // Resize vector to remove trailing elements
    numbers.erase(newEnd, numbers.end());

    // Print the unique elements
    std::cout << "After removing consecutive duplicates: ";
    for (const auto& num : numbers) {
        std::cout << num << " ";
    }
    std::cout << std::endl;

    return 0;
}
After removing consecutive duplicates: 1 2 3 4 5

Key Points:

  • std::unique only removes consecutive duplicates; sort the vector first if all duplicates need to be removed.
  • It does not actually reduce the vector size; use erase to resize the vector.

Partitioning Elements: std::partition

The std::partition algorithm rearranges elements in a vector based on a condition, but it does not guarantee the relative order of elements. To preserve the original order while grouping elements, use std::stable_partition. Both algorithms can group elements to be removed at the end of the vector, which can then be erased.

Using std::partition
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8};

    // Partition elements into odd and even while maintaining relative order
    auto partition_point = std::stable_partition(
        numbers.begin(),
        numbers.end(),
        [](int n) { return n % 2 != 0; } // Keep odd numbers at the beginning
    );

    // Remove even numbers
    numbers.erase(partition_point, numbers.end());

    // Print the remaining elements
    std::cout << "After partitioning and removing even numbers: ";
    for (const auto& num : numbers) {
        std::cout << num << " ";
    }
    std::cout << std::endl;

    return 0;
}
After partitioning and removing even numbers: 1 3 5 7

Key Points:

  • std::partition rearranges the vector based on a condition, grouping matching elements at the beginning but does not preserve their relative order.
  • Combine std::partition with erase to efficiently remove unwanted elements from the vector.
  • Use std::stable_partition to maintain the original order of elements while grouping them.

Range-Based Erase: std::erase and std::erase_if (C++20)

Starting with C++20, the std::erase and std::erase_if functions offer a convenient way to remove elements from a vector. These functions work directly on the container, eliminating the need to use std::remove followed by erase.

Using std::erase and std::erase_if
#include <iostream>
#include <vector>
#include <algorithm>  // For std::erase_if

int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8};

    // Remove all occurrences of 2
    std::erase(numbers, 2);

    // Remove all even numbers
    std::erase_if(numbers, [](int n) { return n % 2 == 0; });

    // Print remaining elements
    std::cout << "After removing 2s and even numbers: ";
    for (const auto& num : numbers) {
        std::cout << num << " ";
    }
    std::cout << std::endl;

    return 0;
}
After removing 2s and even numbers: 1 3 5 7

Note: std::erase and std::erase_if are available only in C++20 or later. Ensure your compiler supports these features.

Key Points:

  • std::erase: Removes all elements matching a specific value.
  • std::erase_if: Removes elements satisfying a condition.
  • Simplifies code by directly operating on the container.

Best Practices

  • Use pop_back() when removing elements from the end, as it has O(1) complexity.
  • Prefer the erase-remove idiom for removing elements matching a specific value or condition.
  • Consider std::erase/std::erase_if for simpler, more concise code in modern C++ (C++20 or later).
  • Use std::unique for removing consecutive duplicates, especially after sorting the vector if needed.
  • Leverage std::partition for separating elements based on a condition and erasing the unwanted ones.
  • For custom removal logic, iterate manually and carefully handle iterator invalidation after erase.
  • Be mindful of performance implications when removing elements frequently, especially in large vectors.
  • Call shrink_to_fit() if memory usage is critical after removing elements, as erase does not reduce capacity.

Performance Tip: If you need to remove many elements, consider marking them for removal first (e.g., using a flag) and then removing them in a single operation using the erase-remove idiom or std::erase_if.

Conclusion

We explored various techniques for removing elements from vectors in C++, from basic methods to modern approaches like std::erase_if and std::unique. Selecting the right method depends on your use case and C++ version.

Congratulations on completing this guide! We hope you now feel confident in applying these techniques to handle vector element removal effectively.

For more advanced topics, performance tips, and related C++ tutorials, don’t forget to explore our Further Reading section.

Have fun and happy coding!

Further Reading

Expand your knowledge with these additional resources. Whether you're looking for official documentation or practical tools, these links will help you dive deeper into the concepts covered in this guide.

Attribution and Citation

If you found this guide and tools helpful, feel free to link back to this page or cite it in your work!

Profile Picture
Senior Advisor, Data Science | [email protected] |  + posts

Suf is a senior advisor in data science with deep expertise in Natural Language Processing, Complex Networks, and Anomaly Detection. Formerly a postdoctoral research fellow, he applied advanced physics techniques to tackle real-world, data-heavy industry challenges. Before that, he was a particle physicist at the ATLAS Experiment of the Large Hadron Collider. Now, he’s focused on bringing more fun and curiosity to the world of science and research online.

Buy Me a Coffee ✨