Std::vector против std:: array в С++

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

Ответ 1

std::vector - это класс шаблонов, который инкапсулирует динамический массив 1 хранящийся в куче, который растет и сжимается автоматически, если элементы добавляются или удаляются. Он предоставляет все крючки (begin(), end(), итераторы и т.д.), Которые делают его работу с остальной частью STL. Он также имеет несколько полезных методов, которые позволяют выполнять операции, которые на обычном массиве будут громоздкими, например, например. вставляя элементы в середине вектора (он обрабатывает всю работу по перемещению следующих элементов за кулисами).

Поскольку он хранит элементы в памяти, выделенные в куче, он имеет некоторые накладные расходы в отношении статических массивов.

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

Он более ограничен, чем std::vector, но он часто более эффективен, особенно для небольших размеров, потому что на практике это в основном облегченная оболочка вокруг массива C-стиля. Тем не менее, он более безопасен, поскольку неявное преобразование в указатель отключено, и оно обеспечивает большую часть связанных с STL функций std::vector и других контейнеров, поэтому вы можете легко использовать его с алгоритмами STL и co. Во всяком случае, для самого ограничения фиксированного размера он гораздо менее гибкий, чем std::vector.

Для введения в std::array, посмотрите эту статью; для быстрого ознакомления с std::vector и с возможными операциями, вы можете посмотреть документацию .


  • На самом деле, я думаю, что в стандарте они описываются с точки зрения максимальной сложности различных операций (например, случайный доступ в постоянное время, итерация по всем элементам в линейном времени, добавление и удаление элементов на конец в постоянном амортизированном времени и т.д.), но AFAIK нет другого метода выполнения таких требований, кроме использования динамического массива. Как указано в @Lucretiel, стандарт фактически требует, чтобы элементы хранились соприкасаемо, так что это динамический массив, который хранится там, где его назначает соответствующий распределитель.

Ответ 2

Использование класса std::vector<T>:

  • ... так же быстро, как и встроенные массивы, предполагая, что вы делаете только то, что позволяют встроенные массивы (чтение и запись в существующие элементы).

  • ... автоматически изменяет размер при вставке новых элементов.

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

  • ... позволяет выполнить проверенное диапазоном чтение с помощью метода at() (вы всегда можете использовать индексы [], если вы не хотите, чтобы эта проверка выполнялась).

В std::vector<T> std::vector<T> есть два:

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

  • Класс std::vector<bool> глупо. Он реализован как сжатое битовое поле, а не как массив. Избегайте его, если вам нужен массив bool s!

  • Во время использования std::vector<T> будет немного больше, чем массив С++ с таким же количеством элементов. Это связано с тем, что им необходимо отслеживать небольшую часть другой информации, такой как их текущий размер, и потому, что когда размер std::vector<T> изменяется, они оставляют больше места, чем нужно. Это делается для того, чтобы не изменять их каждый раз при вставке нового элемента. Такое поведение можно изменить, предоставив пользовательский allocator, но я никогда не чувствовал необходимости делать это!


Изменить: прочитав ответ Зуда на вопрос, я почувствовал, что должен добавить это:

Класс std::array<T> не совпадает с массивом С++. std::array<T> - очень тонкая оболочка вокруг массивов С++, с основной целью скрытия указателя от пользователя класса (в С++ массивы неявно отображаются в качестве указателей, что часто приводит к ужасающему эффекту). Класс std::array<T> также сохраняет свой размер (длину), что может быть очень полезно.

Ответ 3

Чтобы подчеркнуть точку, сделанную @MatteoItalia, разница в эффективности заключается в том, где хранятся данные. Память кучи (требуется с vector) требует вызова системы для выделения памяти, и это может быть дорого, если вы считаете циклы. Память стека (возможная для array) практически равна нулю с точки зрения времени, поскольку память распределяется путем простой настройки указателя стека, и она выполняется только один раз при входе в функцию. Стек также предотвращает фрагментацию памяти. Разумеется, std::array не всегда будет в стеке; это зависит от того, где вы его выделяете, но все равно будет включать в себя еще одно распределение памяти из кучи по сравнению с вектором. Если у вас есть

  • small "array" (менее 100 элементов) - (типичный стек составляет около 8 МБ, поэтому не выделяйте более нескольких килобайт в стеке или меньше, если ваш код рекурсивный)
  • размер будет исправлен.
  • время жизни находится в области функций (или является значением члена с тем же временем жизни, что и родительский класс)
  • вы считаете циклы,

определенно используйте std::array над вектором. Если какое-либо из этих требований неверно, используйте std::vector.

Ответ 4

Если вы планируете использовать многомерные массивы, то есть одно дополнительное различие между std:: array и std::vector. Многомерный std:: array будет иметь элементы, упакованные в память во всех измерениях, так же, как и в стилевом массиве style. Многомерный std::vector не будет упакован во всех измерениях.

Учитывая следующие объявления:

int cConc[3][5];
std::array<std::array<int, 5>, 3> aConc;
int **ptrConc;      // initialized to [3][5] via new and destructed via delete
std::vector<std::vector<int>> vConc;    // initialized to [3][5]

Указатель на первый элемент в массиве c-style (cConc) или std:: array (aConc) можно повторить по всему массиву, добавив 1 к каждому предыдущему элементу. Они плотно упакованы.

Указатель на первый элемент в векторном массиве (vConc) или массив указателей (ptrConc) может быть повторен только через первые 5 (в данном случае) элементов, а затем есть 12 байтов (в моей системе) накладные расходы для следующего вектора.

Это означает, что массив std::vector > , инициализированный как массив [3] [1000], будет намного меньше в памяти, чем один, инициализированный как массив [1000] [3], и оба будут больше в памяти, чем std: массив, выделенный в любом случае.

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

Ответ 5

Одно из преимуществ, которое векторы имеют над массивами, состоит в том, что можно найти текущий размер вектора, используя vector_name.size().

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

Ответ 6

Вектор - это контейнерный класс, а массив - выделенная память.