2010-04-23 6 views
8

Я хотел бы «усаживать в соответствие» std::vector, чтобы уменьшить его объем до его точного размера, чтобы освободить дополнительную память. Стандартный трюк, кажется, один описанный here:Как сжимать-to-fit std :: vector в режиме экономии памяти?

template< typename T, class Allocator > 
void shrink_capacity(std::vector<T,Allocator>& v) 
{ 
    std::vector<T,Allocator>(v.begin(),v.end()).swap(v); 
} 

Всего смысл термоусадочные к приступу, чтобы сэкономить память, но не делает этот метод сначала создать глубокую копию, а затем обменивает экземпляры? Итак, в какой-то момент - когда копия построена - использование памяти удваивается?

Если это так, есть ли более удобный для хранения метод термоусадки? (В моем случае вектор действительно большой, и я не могу позволить себе как оригинал, так и его копию в памяти в любое время.)

+0

Дубликат: http://stackoverflow.com/questions/1111078/reduce-the-capacity-of-an-stl-vector – ergosys

+2

Не совсем, он хочет предотвратить временную копию обоих предметов в памяти при том же когда происходит своп. –

+0

Собственно, об этом и говорит другой вопрос (избегая копии). Спасибо за ссылку. – Frank

ответ

3

Ну, если вы хотите изменить размер массива, что бы вы сделали? Вы должны создать новый и скопировать все значения - будь то индивидуально или с memcpy или что-то еще. Вы не можете изменить размер массива на C или C++.

std::vector в значительной степени гарантированно реализуется с использованием массива для его хранения (IIRC, стандарт не гарантирует, что это массив, но массив - это единственное, что может удовлетворить различные требования API, такие как эффективность каждой операции должна быть, поэтому, фактически, она гарантирована, даже если эта гарантия не является явной). Поскольку он реализован с использованием массива, и вы не можете изменять размеры массивов без копирования, вы не можете изменять размер векторов без копирования.

Вы могли бы теоретически иметь функцию shrink_capacity(), которая спрятала тот факт, что вам пришлось временно более или менее удвоить свои требования к размеру, но поскольку std::vector в настоящее время не имеет такой функции, вы должны фактически сделать явную копию , Трюк с обменом - это отличный способ сделать это.

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

+0

почему не может stl :: Vector просто скажите malloc (или новому), что он больше не нуждается в памяти из последней записи в зарезервированный размер? Тогда распределитель кучи может просто вернуть его в свободный список - не нужно ничего копировать –

+1

@Martin Я никогда не слышал о том, как это сделать.Там realloc, но поскольку у этого нет никакой гарантии, что он вернет тот же блок памяти, вы потеряете все, что было в массиве раньше. Если есть способ сделать это, то я предполагаю, что вектор может это сделать, но в настоящее время он не имеет такой функции, даже если это возможно. –

+5

Поскольку большинство распределителей памяти не работают таким образом; вы не можете отредактировать граничный тег уже выделенного блока, чтобы сделать его меньше на месте, в то же время уступив обратно свободному списку. Некоторые экзотические распределители могут это сделать, но стандартная библиотека не предназначена для их зависимости. – Crashworks

-1

Если ваш новый размер составляет половину оригинала, возможно, вам удастся сменить место размещения нового вектора (или прямого массива dynaimc, если вектор не может этого сделать) в неиспользуемую концевую часть старого , Не уверен, что вектор хранит информацию в этой области памяти, так что это будет очень хаки и страшно. Но это идея.

Теперь, когда я думаю об этом, операция типа memMove(), в которой вы копируете информацию в обратном порядке от последнего индекса, используемого в оригинале, к задней части неиспользуемой области в оригинале, сохранит данные. Если вы сделали это место новым массивом, вы могли бы указать его везде, где новые данные существовали бы посередине в исходной области памяти. Само собой разумеется.