Уменьшить емкость stl-вектора

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

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

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

PS: Я не забочусь о переносном решении, если оно работает для gcc.

Ответ 1

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() изменит только внутреннюю структуру данных.

Ответ 2

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

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

Ответ 3

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

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

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

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

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

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

Ответ 4

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

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

Изменить: я неправильно понял вопрос. Приведенный выше код очистит вектор. OP хочет сохранить элементы нетронутыми, только сжимайте capacity() до size().

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

изменить. Итак, я заглянул в реализацию libstdС++. Кажется, что решение aJ действительно будет работать.

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

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

Ответ 5

Нет, вы не можете уменьшить емкость вектора без копирования. Тем не менее, вы можете контролировать, сколько нового роста распределения, проверяя емкость() и резерв вызовов() каждый раз, когда вы что-то вставляете. Поведение по умолчанию для 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);
}

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

Ответ 6

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

Ответ 7

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

-UBcse

Ответ 8

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

Смотрите: http://en.cppreference.com/w/cpp/container/vector/shrink_to_fit

Ответ 9

Получите книгу "Эффективный STL" Скотта Майерса. Он имеет полный элемент jus по уменьшению векторной емкости.