std :: vector против std :: array в C ++ - PullRequest
       3

std :: vector против std :: array в C ++

257 голосов
/ 13 декабря 2010

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

Ответы [ 5 ]

287 голосов
/ 13 декабря 2010

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

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

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

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

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

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

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

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

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

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

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

Есть два три основныхпредостерегает от использования std::vector<T>:

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

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

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


Редактировать: прочитав ответ Зуда на вопрос, я почувствовалЯ должен добавить это:

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

14 голосов
/ 29 июня 2015

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

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

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

10 голосов
/ 02 марта 2017

Если вы планируете использовать многомерные массивы, то есть одно дополнительное отличие между std :: array и std :: vector.Многомерный std :: array будет иметь элементы, упакованные в память во всех измерениях, так же, как и массив в стиле ac.Многомерный 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 и заставить его работать.

0 голосов
/ 13 декабря 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...