В каких случаях предпочтительнее использовать списки std list а не массивы std vector
в нашем курсе C++ они предлагают больше не использовать массивы C++ в новых проектах. Насколько я знаю, сам Stroustroup предлагает не использовать массивы. Но есть ли существенные различия в производительности?
использование массивов C++ с new (то есть с использованием динамических массивов) следует избегать. Существует проблема, вы должны отслеживать размер, и вам нужно удалить их вручную, и делать все виды домашнего хозяйства.
использование массивов в стеке также не рекомендуется, потому что у вас нет проверки диапазона, и передача массива вокруг потеряет любую информацию о его размере (преобразование массива в указатель). Вы должны использовать boost::array в этом случае, который обертывает массив C++ в небольшой класс и обеспечивает size функция и итераторы для итерации по нему.
теперь std:: vector против собственных массивов C++ (взято из интернета):
Примечание: Если вы выделяете массивы с new и выделять неклассовые объекты (например, plain int ) или классы без пользовательского конструктора и вы не хотите, чтобы ваши элементы были инициализированы изначально, используя new -выделенные массивы могут иметь преимущества в производительности потому что std::vector инициализирует все элементы значениями по умолчанию (0 для int, например) при построении (кредиты @bernie для запоминания меня).
преамбула для людей микро-оптимизатора
"программисты тратят огромное количество времени, думая или беспокоясь о скорости некритических частей своих программ, и эти попытки эффективности на самом деле оказывают сильное негативное влияние при отладке и обслуживании. Мы должны забыть о небольшой эффективности, скажем, о 97% времени:преждевременная оптимизация-корень всех зол. пока мы не должны упускать свои возможности в этих критических 3%".
(спасибо метаморфозы для полной цитаты)
Не используйте массив C вместо вектора (или что-то еще) только потому, что вы считаете, что он быстрее, поскольку он должен быть ниже уровня. Ты ошибаешься.
используйте по умолчанию вектор (или безопасный контейнер, адаптированный к вашим потребностям), а затем, если ваш профилировщик говорит, что это проблема, посмотрите, можете ли вы оптимизировать его, используя лучший алгоритм или изменение контейнера.
об этом сказал, Мы можем вернуться к первоначальному вопросу.
Статический/Динамический Массив?
классы массивов C++ ведут себя лучше, чем низкоуровневый массив C, потому что они много знают о себе и могут ответить на вопросы, которые массивы C не могут. Они способны убирать за собой. И что более важно, они обычно пишутся с использованием шаблонов и / или встраивания, что означает, что то, что кажется многим кодом в debug разрешает мало или нет кода, созданного в сборке выпуска, что не означает разницы с их встроенной менее безопасной конкуренцией.
в целом, он делится на две категории:
динамические массивы
использование указателя на массив malloc-ed/new-ed будет в лучшем случае так же быстро, как версия std:: vector ,и намного менее безопасно (см. litb после).
поэтому используйте std:: vector.
статические массивы
использование статического массива будет в лучшем случае:
- как std:: array версия
- и гораздо менее безопасным.
неинициализированные , С помощью vector вместо сырого буфера возникает видимая стоимость, потому что vector инициализирует буфер при построении, в то время как код, который он заменяет, не сделал, как отмечено Берни в своем ответ.
если это так, то вы можете обработать его с помощью unique_ptr вместо vector или, если случай не является исключительным в вашей кодовой строке, фактически напишите класс buffer_owner это будет владеть этой памятью и даст вам легкий и безопасный доступ к ней, включая бонусы, такие как изменение ее размера (используя realloc ?), или что вам нужно.
векторы-это массивы под капотом. Представление то же самое.
одно место, где вы можете столкнуться с проблемой производительности, не правильно определяет размер вектора для начала.
по мере заполнения вектора он будет изменять размер, и это может означать новое распределение массива, за которым следуют N конструкторов копирования, а затем около n вызовов деструктора, а затем удаление массива.
Если ваша конструкция / деструкт стоит дорого, вам намного лучше сделать вектор правильный размер для начала.
существует простой способ продемонстрировать это. Создайте простой класс, который показывает, когда он построен/уничтожен/скопирован / назначен. Создайте вектор этих вещей и начните толкать их на заднем конце вектора. Когда вектор заполняется, будет каскад активности по мере изменения размера вектора. Затем повторите попытку с вектором, размер которого равен ожидаемому количеству элементов. Вы увидите разницу.
ответить на что-то Мехрдад сказал:
однако могут быть случаи, когда вам все еще нужны массивы. Когда взаимодействие с кодом низкого уровня (т. е. сборка) или старые библиотеки, которые требовать массивы, возможно, вы не сможете использовать векторы.
вообще не верно. Векторы красиво деградируют в массивы / указатели, если вы используете:
это работает для всех основных реализаций STL. В следующем стандарте это будет требуется для работы (хотя сегодня это просто отлично).
у вас еще меньше причин использовать простые массивы в C++11.
есть 3 вида массивов в природе от самого быстрого до самого медленного, в зависимости от особенностей, которые они имеют (конечно, качество реализации может сделать вещи очень быстро даже для случая 3 в списке):
- Static с размером, известным во время компиляции. --- std::array<T, N>
- динамический с размером, известным во время выполнения и никогда не изменялся. Типичная оптимизация здесь заключается в том, что если массив может быть выделяется непосредственно в стеке. -- недоступен. Может быть!--1--> В C++ TS после C++14. В C есть VLAs
- динамический и изменять размер во время выполнения. --- std::vector<T>
на 1. простые статические массивы с фиксированным количеством элементов, используйте std::array<T, N> в C++11.
на 2. массивы фиксированного размера, указанные во время выполнения, но это не изменит их размер, есть обсуждение в C++14, но он был перемещен в техническая спецификация и сделанный из C++14 окончательно.
на 3. std::vector<T> обычно запрашивает память в куче. Это может иметь последствия для производительности, хотя вы можете использовать std::vector<T, MyAlloc<T>> для улучшения ситуации с пользовательский распределитель. Преимущество по сравнению с T mytype[] = new MyType[n]; заключается в том, что вы можете изменить его размер и что он не будет распадаться на указатель, как простые массивы делать.
используйте стандартные типы библиотек, упомянутые, чтобы избежать массивы распадаясь на указатели. Вы сэкономите время отладки и производительность ровно то же самое, что и с обычными массивами, если вы используете тот же набор функций.
STL-сильно оптимизированная библиотека. Фактически, даже предлагается использовать STL в играх, где может потребоваться высокая производительность. Массивы слишком подвержены ошибкам для использования в повседневных задачах. Сегодняшние компиляторы также очень умны и могут действительно производить отличный код с STL. Если вы знаете, что делаете, STL обычно может обеспечить необходимую производительность. Например, инициализируя векторы до требуемого размера (если вы знаете с самого начала), вы можете в основном достичь производительности массива. Однако могут быть случаи, когда вам все еще нужны массивы. При взаимодействии с низкоуровневым кодом (т. е. сборкой) или старыми библиотеками, требующими массивов, вы не сможете использовать векторы.
перейти с STL. Нет никакого штрафа за производительность. Алгоритмы очень эффективны, и они хорошо справляются с деталями, о которых большинство из нас не думает.
вывод заключается в том, что массивы целых чисел быстрее, чем векторы целых чисел (в моем примере 5 раз). Однако массивы и векторы имеют одинаковую скорость для более сложных / не выровненных данных.
Если вы компилируете программное обеспечение в режиме отладки, многие компиляторы не будут вставлять функции доступа вектора. Это сделает реализацию вектора stl намного медленнее в условиях, когда производительность является проблемой. Это также облегчит отладку кода, так как вы можете видеть в отладчике, сколько памяти было выделено.
в оптимизированном режиме я ожидал бы, что вектор stl приблизится к эффективности массива. Это так много методов векторной сейчас встроенный.
разница в производительности между ними очень сильно зависит от реализации - если вы сравните плохо реализованный std:: vector с оптимальной реализацией массива, массив выиграет, но поверните его, и вектор выиграет.
пока вы сравниваете яблоки с яблоками (либо массив, либо вектор имеют фиксированное количество элементов, либо оба изменяются динамически), я бы подумал, что разница в производительности незначительна, пока вы следуете got STL практика кодирования. Не забывайте, что использование стандартных контейнеров c++ также позволяет использовать предварительно свернутые алгоритмы, которые являются частью стандартной библиотеки C++, и большинство из них, вероятно, будут лучше работать, чем средняя реализация того же алгоритма, который вы создаете сами.
тем не менее, IMHO вектор выигрывает в сценарии отладки с debug STL, поскольку большинство реализаций STL с правильным режимом отладки могут по крайней мере выделить / cathc типичные ошибки, сделанные людьми, когда работа со стандартными контейнерами.
О, и не забывайте, что массив и вектор имеют одинаковый макет памяти, поэтому вы можете использовать векторы для передачи данных в устаревший код C или C++, который ожидает базовые массивы. Имейте в виду, что большинство ставок в этом сценарии отключены, и вы снова имеете дело с необработанной памятью.
существует определенно влияние производительности на использование std::vector против необработанного массива, когда вы хотите неинициализированные буфер (например, использовать в качестве назначения для memcpy() ). Ан std::vector инициализирует все его элементы с помощью конструктора по умолчанию. Необработанный массив не будет.
на в C++ спецификаций на std:vector конструктор принимая
Если вам не нужно динамически регулировать размер, у вас есть накладные расходы памяти для сохранения емкости (один указатель/size_t). Вот и все.
может быть некоторый крайний случай, когда у вас есть векторный доступ внутри встроенной функции внутри встроенной функции, где вы вышли за пределы того, что компилятор будет встроен, и он заставит вызов функции. Это было бы так редко, что не стоило бы беспокоиться - в общем, я бы согласился с litb.
Я удивлен, что никто еще не упомянул об этом - не беспокойтесь о производительности, пока не будет доказано, что это проблема, а затем бенчмарк.
Я бы сказал, что главная забота не производительность, а безопасность. Вы можете сделать много ошибок с массивами (например, рассмотреть изменение размера), где вектор сэкономит вам много боли.
векторы используют немного больше памяти, чем массивы, поскольку они содержат размер массива. Они также увеличивают размер жесткого диска программ и, вероятно, объем памяти программ. Эти увеличения незначительны, но могут иметь значение, если вы работаете со встроенной системой. Хотя большинство мест, где эти различия имеют значение, - это места, где вы бы использовали C, а не c++.
следующий простой тест:
противоречит выводам из " сравнения кода сборки, сгенерированного для базовых операций индексирования, разыменования и приращения векторов и массивов/указателей."
там должна быть разница между массивами и векторами. Так написано в тесте. просто попробуйте, код есть.
иногда массивы действительно лучше, чем векторы. Если ты всегда манипулируешь набор объектов фиксированной длины, массивы лучше. Рассмотрим следующие фрагменты кода:
где векторная версия X является
и версия массива X:
версия массива будет main() будет быстрее, потому что мы избегаем накладные расходы "нового" каждый раз во внутреннем цикле.
Что лучше: динамические массивы, векторы, списки, map контейнеры или что-то ещё?
Привет всем! Помогите правильно алгоритм выбрать. Надо получать из файлов (около 8000 файлов).
Что лучше С++ 6 или С++ 2010 Что выбрать, мое мнение
Что лучше С++ 6 или С++ 2010 Что выбрать, мое мнение Вот я тут на днях думал и пришел к выводу.
Глобальные и локальные переменные: что лучше (или что для чего и в чем конкретная разница)?
Что лучше (или как надо (или что для чего и в чем конкретная разница)): 1. // объявление в.
Помощь в написании контрольных, курсовых и дипломных работ здесь.
В чем разница между динамическим массивом и статическим?
ребята, я не понимаю различия. вроде читал литературу. ну вот говорят, что динамический массив.
В чем разница между обычным массивом и контейнером
В чем разница между обычным массивом и контейнером?
В чем разница между массивом строк и List<string>?
А есть ли принципиальная разница между string array1 и List<string> array2 ? И если есть, то в.
Разница между списком и вектором
вот допустим в с++ есть такая тема как списки. препод мой по проги говорит ,что с помощью них можно.
Я никогда не использовал std::list<T> сам. Мне было интересно, когда люди используют его, когда у нас уже есть std::vector<T> что похоже на массивы с непрерывной памятью. std::vector кажется идеальным выбором, когда нам нужен последовательный контейнер!
- когда именно вы предпочитаю std::list над std::vector ? и почему именно?
- когда вы предпочитаю std::vector над std::list ? и почему?
если рассмотрение представления, то пожалуйста перечислите их слишком с подробным объяснением/информацией.
если возможно, процитируйте некоторые ссылки также, чтобы поддержать ваш ответ.
списки лучше вставлять или удалять в любом месте посередине, векторы лучше вставлять в конце.
векторы для доступа к элементам.
это артефакт того, как они реализованы.
Итак, если коллекция изменяется очень мало (по сравнению с доступом) или изменения сосредоточены в конце, я бы использовал вектор.
Если количество изменений существенно (по сравнению с доступом) , и они не находятся на концы, я бы использовал список.
в качестве примера, чтение в коллекции при запуске программы и вряд ли когда-либо ее изменение (или если изменения добавляются в конец), это будет хорошим кандидатом на вектор.
с другой стороны, приложение телефонной книги для особенно популярной и непостоянной рок-звезды, я бы посмотрел на список. На самом деле я бы искал соединение с базой данных, но это был лучший пример, который я мог придумать в кратчайшие сроки :-)
Что касается ссылок, то последние черновики C++0x частично (23.3.4, списки):
список-это контейнер последовательности, который поддерживает двунаправленные итераторы и позволяет выполнять операции вставки и стирания в любом месте последовательности с автоматическим управлением хранилищем. В отличие от векторов и декв, быстрый случайный доступ к элементам списка не поддерживается.
раздел 23.3.5 (о векторах):
вектор является контейнером последовательности, который поддерживает итераторы произвольного доступа. Кроме того, он поддерживает (амортизированные) операции вставки и стирания постоянного времени в конце; вставка и стирание в середине занимают линейное время.
Итак, мой вопрос: когда именно вы предпочитаю std::list над std::vector ?
когда мне нужен последовательный контейнер в чувствительной области и профилирования показывает std::list быстрее.
до сих пор этого никогда не случалось со мной.
(у меня может возникнуть соблазн попробовать std::list первый, когда мне придется хранить очень большие объекты с большим количеством вставки/удаления в середине. Однако в практика, я никогда не сталкивался с таким прецедентом.)
есть несколько компромиссов, которые следует учитывать при выборе между std::list и std:: vector. Также std:: list не о непрерывной памяти, это может быть очень полезно, если вы не можете позволить себе аннулирование итератора или если вам нужна амортизированная постоянная вставка времени в начало/середину/конец.
только (несколько) раз я предпочел std::list из-за list::splice функции-члена. Если вы перетасовываете поддиапазоны в списке или между списками, эта операция может быть значительно быстрее, чем использование std::vector .
Мне не нужно повторять основы, но то, что я узнал трудным путем, заключается в том, что если производительность вставки актуальна, и у вас есть "большие" объекты, то вы должны действительно рассмотрим std:: list,даже Если вы только вставляете в конце. (Ну, список или, возможно, вектор smart pointer / ptr_vector.)
У нас были некоторые случаи использования, когда нам приходилось создавать коллекции априорно неизвестного размера структур нескольких небольших std:: string и использовать std:: вектор полностью убил производительность вставки и добавил не пренебрежимо память.
на проблема с std:: vector в неизвестном графе insert сценарий:
- поскольку вектор всегда будет выделяться, вы платите 50% накладных расходов пространства в худшем случае для типичных реализаций (один вектор строки, где объект имеет, например, 24 байта (MSVC), учитывая скудные 100 000 элементов, может иметь накладные расходы пространства 2 МБ. И это будет умножаться для больших объектов с большим количеством строк или других biggish членов.)
- каждый раз, когда вектор должен перераспределить, он должен скопировать все объекты вокруг, и это не дешево, если у вас есть что-то слабо сложное. Очевидно, что семантика перемещения поможет, но если сами объекты большие, повторная копия все равно может быть актуальной. Не имеет значения, является ли среднее амортизированное время вставки (в конце) теоретически постоянным, если вы копируете все свои объекты muliple раз во время построения вектора. Вы можете заметить этот удар peformance.
- объекты становятся большими очень быстро: структура только из двух пустых std:: string уже имеет не-движимости 48 байт на MSVC.
Это не для bash std:: vector, я все еще использую его по умолчанию-но знаю, чего ожидать от ваших datastructures!
В дополнение к другим ответы, контейнеры node-base ( list /ассоциативные контейнеры) может обеспечить сильный гарантия исключения.
Даже если операция изменения контейнера(например, вставка) вызывает исключение, все указатели/ссылки/итераторы на элементы остаются действительный.
Однако контейнеры линейной памяти(кусочно-непрерывная ячейка памяти) могут предоставляем только базовую гарантию. Когда вставка бросает, даже если вставка на самом деле не выполненный, указатели/ссылки/итераторы могут быть признаны недействительными (хотя сам контейнер можно безопасно уничтожить).
вы используете std:: list, когда вам нужно часто изменять последовательность в других местах, чем спереди или сзади. Накладные расходы таких операций велики в std:: vector в сравнении std:: list.
используйте список, когда его семантика недействительности и характеристики производительности соответствуют вашим требованиям.
List может вставлять / стирать / соединять в любом месте O (1), и это не делает недействительными никакие итераторы. Вектор O (n) для вставки/стирания, за исключением конца, и даже тогда только для вставки, если размер
std::list является моим предпочтительным почти исключительно для одного свойства, которое vector не разделяет, и это знание моих указателей в list всегда будет действителен. Из-за этого я могу использовать это, чтобы содержать все экземпляры любого актива, который мне нужен в одной области, а также давать ссылки на другие объекты для использования. Лучшим примером, который я мог бы придумать, был бы загрузчик изображений, который хранит только одну копию пикселей в памяти, предоставляя указатели на несколько объектов, чтобы они все могут черпать из него.
все vector имеет для него O (1) время доступа. Хотя это звучит как огромный актив, на практике мне очень редко нужно получать доступ к элементам в структуре данных вне перехода от "первого" к "последнему"
одна проблема заключается в том, что векторные изображения гораздо лучше расположения ссылок, и большой прирост производительности в результате этого будет во многих случаях перевешивать преимущества более (алгоритмически) эффективных операций для таких вещей, как удаление и вставка в связанный список.
таким образом, часто std::vector будет превосходить std::list, даже если вы выполняете определенное количество операций, для которых список будет более естественным (например, произвольное удаление элемента, вставка в произвольной позиции или сращивание).
но обратите внимание, что, даже когда вы do выполните много таких операций, вам может быть лучше "разместить" свой список в непрерывном буфере std::vector.
в конкретном случае, когда вам нужно удалить произвольные элементы, но не нужно вставлять в произвольные позиции или сращивание, хорошей альтернативой полномасштабному связанному списку может быть просто пометить записи как "мертвые" и пропустить эти мертвые записи во время итерации.
вы должны использовать список, когда вы делаете много удалений / вставок.
вектор можно использовать, если общий размер элементов не сильно меняется,и если вы делаете некоторые замены.
Читайте также: