C++ <vector> оператор operator[]

класс контейнера C++ <vector>


Среди всех способов доступа к элементам vector,operator[]— самый распространённый и прямой вариант, точно так же, как доступ к элементам массива.

operator[]— это оператор индексации классов-контейнеров, используемый длявозврата элемента в указанной позиции, но он не выполняет проверку границ. Его использование точно такое же, как у обычного массива.

operator[]обеспечивает возможность произвольного доступа в стиле массива, позволяя быстро обращаться к элементам в любой позиции.

Определения слов: operator[]— это оператор индексации, а квадратные скобки — символ доступа к массиву.


Базовый синтаксис и параметры

operator[]— это функция-член класса-контейнера. Просто используйте её так же, как массив.

Формат синтаксиса

reference operator[](size_type pos);
const_reference operator[](size_type pos) const;

Описание параметра

  • Параметр: pos
    • Тип:size_type(беззнаковый целочисленный тип, обычноsize_t)
    • Описание: позиция (индекс) элемента, к которому нужно получить доступ. Индекс начинается с 0, а максимальный допустимый индекс равенsize() - 1。

Описание функции

  • Возвращаемое значение: возвращает ... элемента в указанной позицииСсылка. Если контейнер является константным контейнером, возвращается константная ссылка.
  • Эффект: возвращает элемент в указанной позиции. Проверка границ не выполняется; доступ за границы приводит к неопределённому поведению.
  • Отличие от at(): operator[]Не выполняет проверку границ, поэтому работает немного быстрее;at()выполняет проверку границ и выбрасывает исключение при выходе за границы.

Пример

Давайте основательно освоим его с помощью серии примеров — от простых к сложным.operator[]Использование.

Пример 1: Базовое использование - доступ к элементам

Пример

#include <iostream>
#include <vector>

int main() {
    // 1. Создайте вектор и добавьте несколько элементов
    std::vector<int> numbers = {10, 20, 30, 40, 50};

    std::cout << "Размер вектора: " << numbers.size() << std::endl;

    // 2. Используйте operator[] для доступа к элементам
    std::cout << "Первый элемент [0]: " << numbers[0] << std::endl;
    std::cout << "Второй элемент [1]: " << numbers[1] << std::endl;
    std::cout << "Третий элемент [2]: " << numbers[2] << std::endl;
    std::cout << "Последний элемент [4]: " << numbers[4] << std::endl;

    // 3. Использование цикла для доступа ко всем элементам
    std::cout << "Все элементы: ";
    for(size_t i = 0; i < numbers.size(); ++i) {
        std::cout << numbers[i] << " ";
    }
    std::cout << std::endl;

    return 0;
}

Ожидаемый вывод:

vector的大小是: 5
第一个元素 [0]: 10
第二个元素 [1]: 20
第三个元素 [2]: 30
最后一个元素 [4]: 50
所有元素: 10 20 30 40 50

Анализ кода:

  1. numbers[0]Возвращает первый элемент10(индексы начинаются с 0).
  2. numbers[4]возвращает последний элемент50(потому чтоsize()равно 5, а допустимые индексы — 0-4).
  3. используя циклы иoperator[]может обходить все элементы, и его использование точно такое же, как у массива.

Пример 2: Изменение значений элементов

operator[]возвращает ссылку, поэтому его можно использовать для изменения значения элемента.

Пример

#include <iostream>
#include <vector>

int main() {
    std::vector<int> numbers = {10, 20, 30};

    std::cout << "До изменения: ";
    for(size_t i = 0; i < numbers.size(); ++i) {
        std::cout << numbers[i] << " ";
    }
    std::cout << std::endl;

    // Используйте operator[] для получения ссылки и изменения элементов
    numbers[0] = 100;
    numbers[1] = 200;
    numbers[2] = 300;

    std::cout << "After modification: ";
    for(size_t i = 0; i < numbers.size(); ++i) {
        std::cout << numbers[i] << " ";
    }
    std::cout << std::endl;

    return 0;
}

Ожидаемый вывод:

修改前: 10 20 30
修改后: 100 200 300

Анализ кода:

  • numbers[0] = 100;Значение первого элемента было изменено через ссылку.
  • Это демонстрируетoperator[]возвращает изменяемую lvalue-ссылку.

Пример 3: Использование auto для автоматического вывода типа

Комбинацияautoключевое слово, для более удобного использованияoperator[]。

Пример

#include <iostream>
#include <vector>
#include <string>

int main() {
    std::vector<std::string> names = {"Alice", "Bob", "Charlie"};

    // Используйте auto для автоматического вывода типа
    for(size_t i = 0; i < names.size(); ++i) {
        auto& name = names[i]; // Выводится как std::string&
        std::cout << "Раунд " << (i + 1) << " человек: " << name << std::endl;
    }

    return 0;
}

Ожидаемый вывод:

第 1 个人: Alice
第 2 个人: Bob
第 3 个人: Charlie

Анализ кода:

  • auto& name = names[i];Автоматически выводится какstd::string&, что позволяет напрямую изменять элемент.
  • Пример 4: Разница между operator[] и at()

    Сравнениеoperator[]иat()Различия в поведении.

    Пример

    #include <iostream>
    #include <vector>
    #include <stdexcept>

    int main() {
        std::vector<int> numbers = {10, 20, 30};

        // operator[] не выполняет проверку границ; доступ за границы — на ваш риск
        // Здесь происходит доступ к numbers[5], но size() возвращает 3, это неопределённое поведение
        // Для демонстрации мы обращаемся только к допустимому диапазону

        std::cout << "доступ через operator[]:" << std::endl;
        for(size_t i = 0; i < 3; ++i) {
            std::cout << "numbers[" << i << "] = " << numbers[i] << std::endl;
        }

        std::cout << "\nдоступ через at() (с проверкой границ):" << std::endl;
        for(size_t i = 0; i < 3; ++i) {
            std::cout << "numbers.at(" << i << ") = " << numbers.at(i) << std::endl;
        }

        std::cout << "\nСовет: используйте operator[], когда уверены, что индекс не выйдет за границы, << std::endl;
        std::cout << " Используйте at(), когда не уверены, чтобы получить защиту через исключения." << std::endl;

        return 0;
    }

    Анализ кода:

    • operator[]Доступ быстрее, потому что проверка границ не выполняется.
    • at()Безопаснее, но с накладными расходами на обработку исключений.
    • Совет по выбору: если индекс гарантированно безопасен (например, переменная цикла от 0 до size()-1), используйтеoperator[]; если индекс поступает из внешнего ввода или может быть неопределённым, используйтеat()。

    Пример 5: Вычисление скалярного произведения векторов

    Использованиеoperator[]Реализуйте операции с векторами.

    Пример

    #include <iostream>
    #include <vector>

    // Вычислить скалярное произведение двух векторов
    int dotProduct(const std::vector<int>& v1, const std::vector<int>& v2) {
        int result = 0;
        for(size_t i = 0; i < v1.size(); ++i) {
            result += v1[i] * v2[i];
        }
        return result;
    }

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

        int result = dotProduct(v1, v2);

        std::cout << "Вектор v1: ";
        for(size_t i = 0; i < v1.size(); ++i) {
            std::cout << v1[i] << " ";
        }
        std::cout << std::endl;

        std::cout << "Вектор v2: ";
        for(size_t i = 0; i < v2.size(); ++i) {
            std::cout << v2[i] << " ";
        }
        std::cout << std::endl;

        std::cout << "Скалярное произведение: " << result << std::endl;
        // 1*4 + 2*5 + 3*6 = 4 + 10 + 18 = 32

        return 0;
    }

    Ожидаемый вывод:

    向量 v1: 1 2 3
    向量 v2: 4 5 6
    点积: 32
    

    Анализ кода:

    • Использованиеoperator[]позволяет быстро обращаться к элементам вектора в алгоритмах.
    • Скалярное произведение вычисляется путём умножения элементов, стоящих на соответствующих позициях, и последующего их суммирования.

    класс контейнера C++ <vector>

    Другие расширения