Программирование

Как удалить элемент из std::vector по индексу в C++

Узнайте, как удалить элемент из std::vector по индексу в C++ с помощью erase. Переведите индекс в итератор, проверьте границы и убедитесь, что он в размере.

Как удалить элемент из std::vector по индексу?

Я работаю с std::vector<int> и мне нужно удалить n‑й элемент. Как правильно использовать erase?

Например:

cpp
std::vector<int> vec;

vec.push_back(6);
vec.push_back(-17);
vec.push_back(12);

vec.erase(???);

Что нужно написать вместо ???, чтобы удалить, скажем, второй элемент?

Чтобы удалить элемент из std::vector по индексу, нужно превратить индекс в итератор и передать его в метод erase. Например, чтобы удалить второй элемент (индекс 1), просто вызовите vec.erase(vec.begin() + 1).

Понимание std::vector::erase

Метод std::vector::erase предназначен для работы с итераторами, а не с «сырыми» индексами. Это основная идея контейнеров STL: обычно вы работаете с итераторами, а не с числами.

Согласно документации стандарта C++, у метода erase есть два основных перегрузки:

  1. iterator erase(iterator position) – удаляет один элемент по указанной позиции
  2. iterator erase(iterator first, iterator last) – удаляет диапазон элементов

Поскольку векторы предоставляют итераторы произвольного доступа, вы можете легко преобразовать индекс в итератор, используя арифметические операции.

Базовый синтаксис удаления по индексу

Общий шаблон удаления элемента по индексу n выглядит так:

cpp
vector.erase(vector.begin() + n);

Где:

  • vector.begin() возвращает итератор на первый элемент
  • + n перемещает итератор на n позиций вперёд
  • Таким образом, получается итератор, указывающий на элемент с индексом n

Полный пример удаления второго элемента

Вот ваш пример с правильной реализацией:

cpp
#include <iostream>
#include <vector>

int main() {
    std::vector<int> vec;
    
    vec.push_back(6);
    vec.push_back(-17);
    vec.push_back(12);
    
    // Удаляем второй элемент (индекс 1)
    vec.erase(vec.begin() + 1);
    
    // Теперь vec содержит: 6, 12
    for (int num : vec) {
        std::cout << num << " ";
    }
    // Вывод: 6 12
    
    return 0;
}

Распространённые ошибки и лучшие практики

Ошибка 1: Использование индекса напрямую

cpp
// НЕПРАВИЛО – erase не принимает индекс напрямую
vec.erase(1); // Это вызовет ошибку компиляции

Ошибка 2: Неправильная индексация

Помните, что индексы вектора начинаются с нуля, поэтому:

  • Индекс 0: первый элемент
  • Индекс 1: второй элемент
  • Индекс 2: третий элемент

Лучший подход: проверка границ

cpp
if (index < vec.size()) {
    vec.erase(vec.begin() + index);
} else {
    // Обработать ошибку: индекс вне диапазона
}

Лучший подход: использовать size_t для индекса

cpp
size_t index = 1;
if (index < vec.size()) {
    vec.erase(vec.begin() + index);
}

Альтернативные подходы

Подход 1: Использование std::next (C++11 и новее)

cpp
vec.erase(std::next(vec.begin(), index));

Подход 2: идиом remove для нескольких элементов

Если нужно удалить несколько элементов, используйте диапазонный erase:

cpp
// Удаляем элементы с индекса 1 по 2 (включительно)
vec.erase(vec.begin() + 1, vec.begin() + 3);

Подход 3: использование алгоритмов

Для условного удаления используйте идиом erase‑remove:

cpp
// Удаляем все элементы, равные -17
vec.erase(std::remove(vec.begin(), vec.end(), -17), vec.end());

Показатели производительности

  • Временная сложность: O(n), где n — количество элементов после удаляемого
  • Причина: при удалении элемента все последующие элементы сдвигаются влево
  • Память: вектор может уменьшить свою ёмкость, если она значительно превышает необходимую

Если часто удаляете элементы из середины больших векторов, подумайте о других контейнерах, например std::list (O(1) для удалений) или std::deque (лучше, чем vector, для вставок/удалений в середине).

cpp
std::vector<int> large_vec(1000000); // Большой вектор
large_vec.erase(large_vec.begin() + 500000); // Это будет медленно из‑за сдвига

Заключение

Вкратце, чтобы удалить элемент из std::vector по индексу, просто превратите индекс в итератор с помощью vector.begin() + index и передайте его в erase. Не забывайте, что индексы начинаются с нуля, и всегда проверяйте, чтобы индекс не выходил за пределы, иначе получите неопределённое поведение. Поскольку erase стоит O(n) из‑за сдвига, возможно, стоит перейти на другой контейнер, если вы часто удаляете элементы из середины больших векторов.

Источники

  1. C++ Reference - std::vector::erase
  2. CPlus365 - C++ Vectors
  3. cppreference.com - Vector Operations
Авторы
Проверено модерацией
Модерация