6 ответов:
std::vectorЭто класс шаблона, который инкапсулирует динамический массив1, хранится в куче, которая растет и сжимается автоматически, если элементы добавляются или удаляются. Он обеспечивает все крючки (begin(),end(), итераторы и т. д.), которые заставляют его работать нормально с остальной частью STL. Он также имеет несколько полезных методов, которые позволяют выполнять операции, которые на обычном массиве были бы громоздкими, например, вставка элементов в середине вектора (он обрабатывает всю работу перемещения следующие элементы за кулисами).поскольку он хранит элементы в памяти, выделенной в куче, он имеет некоторые накладные расходы в отношении статических массивов.
std::array- это класс шаблона, который инкапсулирует массив статического размера, хранящийся внутри самого объекта, что означает, что при создании экземпляра класса в стеке сам массив будет находиться в стеке. Его размер должен быть известен во время компиляции (оно передается как параметр шаблона), и он не может расти или сокращаться.это более ограничено, чем
std::vector, но это часто более эффективно, особенно для небольших размеров, потому что на практике это в основном легкая обертка вокруг массива C-стиля. Тем не менее, это более безопасно, так как неявное преобразование в указатель отключено, и оно предоставляет большую часть связанных с STL функцийstd::vectorи других контейнеров, поэтому вы можете легко использовать его с алгоритмами STL & co. Во всяком случае, для самого ограничения фиксированного размера это гораздо менее гибко, чемstd::vector.на
std::arrayпосмотри в этой статье; для быстрого введения вstd::vectorи к операциям, которые возможны на нем, вы можете посмотреть на его документация.
на самом деле, я думаю, что в стандарте они описаны в терминах максимальной сложности различных операций (например, произвольный доступ в постоянное время, итерация по всем элементам в линейное время, добавление и удаление элементов в конце в постоянное амортизированное время и т. д.), Но AFAIK нет другого способа выполнения таких требований, кроме использования динамического массива.как указано @Lucretiel, стандарт фактически требует, чтобы элементы хранились последовательно, поэтому это динамический массив, хранящийся там, где соответствующий распределитель помещает его.
С помощью
std::vector<T>класс:
...это быстро как использование встроенных массивов, предполагая, что вы делаете только то, что встроенные массивы позволяют вам делать (чтение и запись в существующие элементы).
...автоматически изменяет размер при вставке новых элементов.
...позволяет вставлять новые элементы в начале или в середине вектора, автоматически "сдвигая" остальные элементы "вверх" (имеет ли это смысл?). Это позволяет удалять элементы в любом месте
std::vectorтоже автоматически сдвигает остальные элементы вниз....позволяет выполнять чтение с проверкой диапазона с помощью
at()способ (вы всегда можете использовать индексаторы[]Если вы не хотите, чтобы эта проверка должна быть выполнена).здесь
дватри основных ограничений по использованиюstd::vector<T>:
у вас нет надежного доступа к базовому указателю, который мая это проблема, если вы имеете дело со сторонними функциями, которые требуют адрес массива.
The
std::vector<bool>класс-это глупо. Он реализован как сжатое битовое поле, а не как массив. Избегайте его, если вы хотите массивbools!при использовании
std::vector<T>s будет немного больше, чем C++ массива с одинаковым количеством элементов. Это потому, что они должны отслеживать небольшое количество другой информации, например, их текущий размер, и потому, что всякий раз, когдаstd::vector<T>s изменить размер, они оставляют больше места, чем им нужно. Это делается для того, чтобы предотвратить их от необходимости изменять размер каждый раз, когда новый элемент вставляется. Это поведение можно изменить, предоставив пользовательскийallocator, но я никогда не чувствовал необходимости делать это!
изменить: после прочтения ответа зуда на вопрос, я чувствовал, что должен добавить это:
The
std::array<T>класс не совпадает с массивом C++.std::array<T>- это очень тонкая оболочка вокруг массивов C++, с основной целью скрыть указатель от пользователя класса (в C++ массивы неявно приводятся как указатели, часто для пугающего эффекта). Элементstd::array<T>класс также сохраняет свой размер (длину), что может быть очень полезно.
чтобы подчеркнуть точку, сделанную @MatteoItalia, разница в эффективности заключается в том, где хранятся данные. Куча памяти (требуется с
vector) требует вызова системы для выделения памяти, и это может быть дорого, если вы подсчитываете циклы. Память стека (возможно дляarray) практически "нулевые накладные расходы" с точки зрения времени, потому что память выделяется просто регулируя указатель стека, и это делается только один раз при входе в функцию. Стек также позволяет избежать фрагментации памяти. Конечно,std::arrayне всегда будет в стеке; это зависит от того, где вы его выделяете, но он все равно будет включать в себя одно меньше выделения памяти из кучи по сравнению с вектором. Если у вас есть
- малый "массив" (под 100 элементами говорят) - (типичный стек составляет около 8 МБ, поэтому не выделяйте больше нескольких КБ в стеке или меньше, если ваш код рекурсивен)
- размер будет исправлено
- время жизни находится в области действия функции (или является значением элемента с то же время жизни, что и родительский класс)
- ты считаешь циклы,
наверняка использовать
std::arrayза вектор. Если какой-либо из этих требований не соответствует действительности, то используйтеstd::vector.
Если вы рассматриваете использование многомерных массивов, то есть еще одно дополнительное различие между std::array и std::vector. Многомерный массив std::будет иметь элементы, упакованные в память во всех измерениях, так же, как массив стиля C. Многомерный вектор std::не будет упакован во всех измерениях.
даны следующие объявления:
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> Array, инициализированный как массив [3][1000], будет намного меньше в памяти, чем один инициализированный как [1000] [3] массив, и оба будут больше в памяти, чем std:массив, выделенный в любом случае.
Это также означает, что вы не можете просто передать многомерный векторный (или указатель) массив, скажем, openGL без учета накладных расходов памяти, но вы можете наивно передать многомерный std::array в openGL и заставить его работать.
одним из преимуществ векторов перед массивами является то, что можно найти текущий размер вектора с помощью vector_name.размер().
Как вы можете себе представить, это может быть весьма полезно в различных ситуациях, где вы можете легко получить количество элементов в array_list.
Comments