Накладные расходы на использование std::vector?
Я знаю, что ручное динамическое выделение памяти - плохая идея в целом, но иногда это лучшее решение, чем, скажем, std::vector
?
Чтобы дать грубый пример, если бы мне пришлось хранить массив n
целые числа, где n
<= 16, скажем. Я мог бы реализовать это с помощью
int* data = new int[n]; //assuming n is set beforehand
или используя вектор:
std::vector<int> data;
Всегда ли лучше использовать std::vector
или могут быть практические ситуации, когда ручное выделение динамической памяти было бы лучшей идеей для повышения эффективности?
8 ответов
Всегда лучше использовать std::vector
/std::array
по крайней мере до тех пор, пока вы не сможете окончательно доказать (посредством профилирования), что T* a = new T[100];
решение значительно быстрее в вашей конкретной ситуации. Это вряд ли произойдет vector
/array
очень тонкий слой вокруг старого массива. Есть некоторые накладные расходы на проверку границ с vector::at
, но вы можете обойти это, используя operator[]
,
Я не могу вспомнить ни одного случая, когда имеет смысл динамически выделять вектор в стиле C. (Я работаю в C++ более 25 лет, и я еще не использовал new[]
Обычно, если я знаю размер заранее, я буду использовать что-то вроде:
std::vector<int> data( n );
чтобы получить уже измеренный вектор, а не с помощью push_back
,
Конечно, если n
очень маленький и известен во время компиляции, я буду использовать std::array
(если у меня есть доступ к C++11) или даже к массиву в стиле C, и просто создайте объект в стекебез динамического выделения. (Такие случаи кажутся редкими в коде, над которым я работаю; небольшие массивы фиксированного размера, как правило, являются членами классов. Где я иногда использую массив в стиле C.)
Если вы знаете размер заранее (особенно во время компиляции), и вам не нужны динамические возможности изменения размера std::vector
, тогда использовать что-то попроще - это нормально.
Тем не менее, это что-то должно быть предпочтительно std::array
если у вас есть C++11 или что-то вроде boost::scoped_array
иначе.
Я сомневаюсь, что эффективность будет значительно выше, если она не приведет к значительному уменьшению размера кода или чего-то еще, но это более выразительно, что в любом случае стоит
Вы должны попытаться избежать C
Массивы в стиле C++
когда возможно. STL
предоставляет контейнеры, которые обычно достаточны для каждой потребности. Просто представьте перераспределение массива или удаление элементов из его середины. Контейнер защищает вас от этого, в то время как вы должны были бы позаботиться об этом сами, и если вы не делали этого сто раз, он довольно подвержен ошибкам.
Исключением является, конечно, если вы решаете проблемы низкого уровня, которые могут не справиться с STL
-containers.
Там уже было некоторое обсуждение по этой теме. Смотрите здесь на SO.
Всегда ли лучше использовать std::vector или могут быть практические ситуации, когда ручное выделение динамической памяти было бы лучшей идеей для повышения эффективности?
Назовите меня простаком, но 99,9999...% случаев я бы просто использовал стандартный контейнер. Выбор по умолчанию должен быть std::vector
, но также std::deque<>
может быть разумным вариантом иногда. Если размер известен во время компиляции, выберите std::array<>
, которая является легкой, безопасной оболочкой массивов в стиле C, которая не требует дополнительных затрат.
Стандартные контейнеры предоставляют функции-члены для указания начального зарезервированного объема памяти, поэтому у вас не будет проблем с перераспределением, и вам не нужно будет помнить delete[]
в ваш массив. Я, честно говоря, не понимаю, почему нужно использовать ручное управление памятью.
Эффективность не должна быть проблемой, так как у вас есть функции-члены-выбрасывающие и не-выбрасывающие для доступа к содержащимся элементам, так что вы можете выбрать, предпочитаете ли вы безопасность или производительность.
std::vector может быть создан с параметром size_type, который создает экземпляр вектора с указанным количеством элементов и который выполняет одно динамическое распределение (так же, как ваш массив), а также вы можете использовать резерв, чтобы уменьшить количество перераспределений по сравнению с время использования.
С точки зрения того, кто часто работает с низкоуровневым кодом на C++, стандартные векторы на самом деле являются просто вспомогательными методами с подстраховкой для классического массива в стиле C. Единственные накладные расходы, с которыми вы столкнулись бы в действительности, — это выделение памяти и проверки безопасности для границ. Если вы пишете программу, которой нужна производительность и вы собираетесь использовать векторы в качестве обычного массива, я бы рекомендовал просто использовать массивы в стиле C вместо векторов. На самом деле вы должны проверять данные, поступающие в приложение, и самостоятельно проверять границы, чтобы избежать проверок при каждом доступе к памяти массива.
Приятно видеть, что другие проверяют различия способов C и способов C++. Чаще всего стандартные методы C++ имеют значительно худшую производительность и более уродливый синтаксис, чем их аналоги C, и обычно это причина, по которой люди называют C++ раздутым. Я думаю, что C++ больше фокусируется на безопасности и делает язык более похожим на JavaScript/C#, даже несмотря на то, что этому языку в принципе не хватает фундамента, чтобы быть таковым.
В n
известен во время компиляции, тогда вы должны выбрать std::array
как:
std::array<int, n> data; //n is compile-time constant
и если n
неизвестно во время компиляции, ИЛИ массив может расти во время выполнения, а затем перейти к std::vector
:
std::vector<int> data(n); //n may be known at runtime
Или в некоторых случаях вы можете также предпочесть std::deque
который быстрее чем std::vector
в каком-то сценарии. Смотрите эти:
Надеюсь, это поможет.