уменьшить емкость вектора STL - PullRequest
26 голосов
/ 10 июля 2009

Есть ли способ уменьшить емкость вектора?

Мой код вставляет значения в вектор (заранее не зная их числа), и когда это заканчивается, векторы используются только для операций чтения.

Полагаю, я мог бы создать новый вектор, сделать .reseve () с размером и копировать элементы, но мне не очень нравится дополнительная операция копирования.

PS: мне нет дела до портативного решения, если оно работает для gcc.

Ответы [ 9 ]

39 голосов
/ 10 июля 2009
std::vector<T>(v).swap(v);

Замена содержимого другим вектором меняет емкость.

  std::vector<T>(v).swap(v); ==> is equivalent to 

 std::vector<T> tmp(v);    // copy elements into a temporary vector
         v.swap(tmp);              // swap internal vector data

Swap () изменит только внутреннюю структуру данных.

35 голосов
/ 10 июля 2009

С C ++ 11 вы можете вызвать функцию-член shrink_to_fit(). В проекте стандарта в разделе 23.2.6.2 говорится:

shrink_to_fit - необязательный запрос уменьшить capacity() до size(). [Примечание: запрос не является обязательным для разрешить широту для специфичные для реализации оптимизации. —Конечная записка]

14 голосов
/ 10 июля 2009

Посмотрите на Скотта Мейерса Эффективный STL, пункт 17.

В принципе, вы не можете напрямую уменьшить размер хранилища std::vector. resize() и reseve() никогда не уменьшат фактический объем памяти контейнера. «Хитрость» заключается в том, чтобы создать новый контейнер нужного размера, скопировать данные и заменить их текущим контейнером. Если мы хотим очистить контейнер, это просто:

std::vector<T>().swap(v);

Если нам нужно скопировать данные, то нам нужно сделать копию:

std::vector<T>(v).swap(v);

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

6 голосов
/ 10 июля 2009

Идиоматическое решение - поменять местами новый вектор.

vector<int>().swap(v);

Редактировать: я неправильно понял вопрос. Код выше очистит вектор. ОП хочет, чтобы элементы оставались нетронутыми, только уменьшите capacity() до size().

Трудно сказать, будет ли код AJ делать это. Я сомневаюсь, что есть портативное решение. Для gcc вам нужно взглянуть на их конкретную реализацию vector.

edit : Итак, я заглянул в реализацию libstdc ++. Похоже, решение aJ действительно будет работать.

vector<int>(v).swap(v);

См. источник , строка 232.

3 голосов
/ 10 июля 2009

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

template <typename T>
void myPushBack(std::vector<T>& vec, const T& val) {
    if (vac.size() + 1 == vac.capacity()) {
        vac.reserve(vac.size() * my_magic_ratio);
    }

    vec.push_back(val);
}

Если вы немного хакерские техники, вы всегда можете передать свой собственный распределитель и сделать все, что вам нужно сделать, чтобы восстановить неиспользованную емкость.

2 голосов
/ 10 июля 2009

Я не говорю, что GCC не может иметь какой-либо метод для выполнения того, что вы хотите без копии, но это было бы сложно реализовать (я думаю), потому что векторам нужно использовать объект Allocator для выделения и освобождения память, и интерфейс для Allocator не включает метод reallocate(). Я не думаю, что это было бы невозможно, но это может быть сложно.

1 голос
/ 07 февраля 2013

Старый поток, я знаю, но в случае, если кто-то просматривает это в будущем ... в C ++ 11 есть shrink_to_fit (), но поскольку это необязательный запрос, поведение будет зависеть от его реализации.

См .: http://en.cppreference.com/w/cpp/container/vector/shrink_to_fit

1 голос
/ 10 июля 2009

Если вы беспокоитесь о накладных расходах вашего вектора, то, возможно, вам стоит использовать другой тип структуры данных. Вы упомянули, что когда ваш код инициализирует вектор, он становится доступным только для чтения. Я бы предложил использовать массив с открытым концом, который позволит программе определять ее емкость во время компиляции. Или, возможно, связанный список будет более подходящим для ваших нужд.
Дай мне знать, если я полностью не понял, к чему ты клонил.

-UBcse

0 голосов
/ 11 сентября 2009

Получите книгу «Эффективный STL» Скотта Майерса. У него есть полный пункт о сокращении емкости вектора.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...