Накладные расходы на использование 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 в каком-то сценарии. Смотрите эти:

Надеюсь, это поможет.

Другие вопросы по тегам