Урок №95. std::vector (векторы)

  Юрий  | 

  |

  Обновл. 24 Янв 2022  | 

 164489

 ǀ   21 

На предыдущем уроке мы рассматривали std::array, который является более безопасной и удобной формой обычных фиксированных массивов в языке C++. Аналогично, в Стандартной библиотеке C++ есть и улучшенная версия динамических массивов (более безопасная и удобная) — std::vector.

В отличие от std::array, который недалеко отходит от базового функционала обычных фиксированных массивов, std::vector идет в комплекте с дополнительными возможностями, которые делают его одним из самых полезных и универсальных инструментов в языке C++.

Векторы

Представленный в C++03, std::vector (или просто «вектор») — это тот же динамический массив, но который может сам управлять выделенной себе памятью. Это означает, что вы можете создавать массивы, длина которых задается во время выполнения, без использования операторов new и delete (явного указания выделения и освобождения памяти). std::vector находится в заголовочном файле vector. Объявление std::vector следующее:

Обратите внимание, что в неинициализированном, что в инициализированном случаях вам не нужно явно указывать длину массивов. Это связано с тем, что std::vector динамически выделяет память для своего содержимого по запросу.

Подобно std::array, доступ к элементам массива может выполняться как через оператор [] (который не выполняет проверку диапазона), так и через функцию at() (которая выполняет проверку диапазона):

В любом случае, если вы будете запрашивать элемент, который находится вне диапазона array, длина вектора автоматически изменяться не будет. Начиная с C++11, вы также можете присваивать значения для std::vector, используя список инициализаторов:

В таком случае вектор будет самостоятельно изменять свою длину, чтобы соответствовать количеству предоставленных элементов.

Нет утечкам памяти!


Когда переменная-вектор выходит из области видимости, то она автоматически освобождает память, которую контролировала (занимала). Это не только удобно (так как вам не нужно это делать вручную), но также помогает предотвратить утечки памяти. Рассмотрим следующий фрагмент:

Если переменной value присвоить значение true, то array никогда не будет удален, память никогда не будет освобождена и произойдет утечка памяти.

Однако, если бы array был вектором, то подобное никогда бы и не произошло, так как память освобождалась бы автоматически при выходе array из области видимости (независимо от того, выйдет ли функция раньше из области видимости или нет). Именно из-за этого использование std::vector является более безопасным, чем динамическое выделение памяти через оператор new.

Длина векторов

В отличие от стандартных динамических массивов, которые не знают свою длину, std::vector свою длину запоминает. Чтобы её узнать, нужно использовать функцию size():



Результат:

The length is: 7

Изменить длину стандартного динамически выделенного массива довольно проблематично и сложно. Изменить длину std::vector так же просто, как вызвать функцию resize():

Результат:

The length is: 7
0 1 2 0 0 0 0

Здесь есть две вещи, на которые следует обратить внимание. Во-первых, когда мы изменили длину array, существующие значения элементов сохранились! Во-вторых, новые элементы были инициализированы значением по умолчанию в соответствие с определенным типом данных (значением 0 для типа int).

Длину вектора также можно изменить и в обратную сторону (обрезать):

Результат:

The length is: 4
0 1 4 7

Изменение длины вектора является затратной операцией, поэтому вы должны стремиться минимизировать количество подобных выполняемых операций.

Заключение


Это вводная статья, предназначенная для ознакомления с основами std::vector. На следующих уроках мы детально рассмотрим std::vector, в том числе и разницу между длиной и ёмкостью вектора, и то, как в std::vector выполняется выделение памяти.

Поскольку переменные типа std::vector могут сами управлять выделенной себе памятью (что помогает предотвратить утечку памяти), отслеживают свою длину и легко её изменяют, то рекомендуется использовать std::vector вместо стандартных динамических массивов.

Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (485 оценок, среднее: 4,86 из 5)
Загрузка...

Комментариев: 21

  1. Ivan:

    Есть ли разница в позиции ключевого слова const в объявлении цикла foreach или оба варианта эквивалентны и обозначают константную ссылку на текущий элемент массива?

    или

  2. Kuchizuke:

    Когда мы пытаемся работать с элементом массива вне диапазона то происходит ошибка времени выполнения, правильно? Ибо с этой ошибкой проект собирается(VS2019).

    1. Роман:

      Поскольку ошибка возникает во время работы кода, а не на этапе компиляции, то это ошибка времени выполнение. При желании можно проверить это, запустив этот код:

      В данном случае код компилируется и начинает работу, и после объявления вектора выполнение кода ставиться на паузу

  3. Ангелина:

    Я не очень поняла один момент, может, кто-то сможет подсказать, буду признательна)
    В начале урока написано: "Начиная с C++11, вы также можете присваивать значения для std::vector, используя список инициализаторов … В таком случае вектор будет самостоятельно изменять свою длину, чтобы соответствовать количеству предоставленных элементов."
    А в конце показывают функцию resize( ), которая делает то же самое, но при этом является затратной.
    Так вооот, насколько затратным будет изменить длину вектора через список инициализаторов и зачем тогда нужна отдельная функция? Только для работы с крупными объемами данных, чтобы не переписывать их все вручную? Или есть ещё что-то?

    1. Jaroshevskii:

      Мне кажется что изменять длину std::vector что через метод resize(), что через список инициализаторов будет одинаково затратным (возможно в будущих уроках это будет более подробно описано).

      Отличие же resize() от списка инициализаторов в том что при вызове метода resize() он изменяет длину std::vector и при этом те элементы которые входят в диапазон размера будет сохранены без изменений.
      Изменения размера с помощью списка инициализаторов изменит не только длину std::vector но и запишит вместо старых элементов новые (те которые были записаны в списке инициализаторов).

  4. Papaya:

    Юрий, вы восхитительны! У вас не только классные уроки, но и абсолютно замечательная система кросс-навигации между ними — на сайт изначально попала в поисках информации про классы. Пойду читать ваши уроки с самого начала, у меня хоть какая-то минимальная база знаний и есть, но всё равно так много новых и полезных штук открываю 🙂

    1. Фото аватара Юрий:

      Спасибо! 🙂

  5. Игорь:

    Доброго времени суток!
    В этой статье нет ни слова про дву-х, трё-х, *N — мерные векторы и массивы пространства имён std. Подозреваю что можно реализовать аналогично указателю на указатель (древовидная структура) массив в массиве, но надеюсь есть способ проще и удобней. Конечно сам доберусь до этого, но надеюсь получить ответ и возможно мой вопрос поможет улучшить/дополнить 95-й урок.

    1. Юрий:

      Это было вводное занятие, поверхностное обозрение темы, написано же в конце. Дальше, естественно, будет подробнее

  6. Oleh:

    Что означает здесь оператор (:)?

    1. Анастасия:

      это синтаксис цикла foreach, означает что element является элементом упорядоченной структуры (массива).

  7. Alexey:

    Отличные статьи, но очень плохо, что в этой не сказано про такую полезную вещь, как добавление элемента в конец вектора:

    После этого 25 добавится в конец вектора v.

  8. Andrey:

    Отличный слог, легко читается. Спасибо.

    P.S. Немного знаком с синтаксисами других языков, и когда читал про в Ваших статьях про стандартные массивы CPP, был озадачен. Оказалось что есть нормальные решения. Можно не только на счетах работать. 🙂

  9. Новичок:

    Спасибо Вам огромное! Буду с нетерпением ждать!

    1. Фото аватара Юрий:

      Спасибо и Вам 🙂

  10. Новичок:

    А когда будет продолжение? Просто очень хочется учится дальше!

    1. Фото аватара Юрий:

      На этой неделе постараюсь две-три статьи опубликовать. Просто сейчас времени мало, сессия скоро.

  11. Хочу пройти ваш курс по c++, после всех уроков какой уровень знаний у меня будет?Я выучу весь c++?

    1. Фото аватара Юрий:

      Вы поймёте всё необходимое для программирования на языке С++.

  12. Zufar:

    Продолжай , всё доступно и понятно! Спасибо за уроки!

    1. Фото аватара Юрий:

      Спасибо, буду продолжать.

Добавить комментарий

Ваш E-mail не будет опубликован. Обязательные поля помечены *