c ++ 11 — Может ли pop_back () когда-либо уменьшить емкость вектора? (C ++)

Согласно стандарту C ++, это std::vector<T>::pop_back() когда-нибудь позволял уменьшить емкость вектора?

Я спрашиваю, потому что я хотел бы иметь гарантию, что следующий код будет не бросить недостаточно памяти исключение:

my_vec.pop_back();
if (...)
my_vec.push_back(...);

Предположим, что my_vec является std::vector<int>,

Я предполагаю, что есть три варианта:

  1. Да, это может происходить в соответствии с C ++ 03 и C ++ 11.

  2. Нет, C ++ 11 запрещает это (но C ++ 03 нет).

  3. Нет, и C ++ 03, и C ++ 11 запрещают это.

Да, мой вопрос связан с Меняет ли std :: vector.pop_back () емкость вектора?, но мой вопрос конкретно о том, что стандарт гарантирует.

Обратите внимание, что принятый ответ в Меняет ли std :: vector.pop_back () емкость вектора? в основном о том, как уменьшить емкость вектора, а не о том, когда это гарантировано не случиться, и не предлагает никаких доказательств своего утверждения о pop_back ().

5

Решение

В соответствии с http://en.cppreference.com/w/cpp/container/vector/pop_back

Нет итераторов или ссылок, кроме back() а также end() признаны недействительными

Поэтому это может не перераспределить. Здесь нет C++11 тег на этой странице, который подразумевает, что это также верно в 03. Я выкопаю ссылки на разделы и отредактирую их для полноты.

Редактировать: Еще лучше: от C++03: [lib.container.requirements] (23.1), пункт 10:

нет erase(), pop_back() или же pop_front() Функция выдает исключение.

Та же формулировка в 23.2.1 / 10 в N3337 (~C++11).

8

Другие решения

Нет. Единственный способ уменьшить емкость вектора — трюк со свопом, как показано Вот. А также C++11 как я упоминаю ниже.

Кроме того, как ссылка говорит:

Удаляет последний элемент в векторе,
эффективно уменьшить размер контейнера на один.

Другими словами, это меняет размер вектора и не его вместимость.

Посмотрите на валидность итератора:

Конечный итератор и любой итератор, указатель и ссылка
ссылка на удаленный элемент недействительна.
Итераторы, указатели и ссылки, ссылающиеся на другие
элементы, которые не были удалены, гарантированно сохранят
ссылаясь на те же элементы, на которые они ссылались до вызова.

В C++11 вы могли бы использовать std::vector<>::shrink_to_fit() для изменения емкости (подробнее см. 1-ю ссылку). (tnx Psyduck). Интересные комментарии ниже ответа, но этот вопрос не о вышеуказанном методе, поэтому, если интересно, прочитайте комментарии.

Обратите внимание, что даже этот метод не гарантирует снижение capacityкак ссылка говорит:

Предлагает контейнеру уменьшить его вместимость, чтобы соответствовать его размеру.

Запрос не является обязательным, и реализация контейнера может свободно оптимизировать иначе> и оставить вектор с емкостью, превышающей его размер.

Это может вызвать перераспределение, но не влияет на размер вектора и не может изменять его> элементы.

Было бы слишком странно, что эта функция не гарантирует сокращения capacity а также pop_back делает, в то время как ссылка второй делает не упоминает что-нибудь важное.

Как я вижу, так как ссылка не упоминает capacity, это означает, что это не нужно, а это значит, что capacity остается такой же.

Интересный пример:

#include <iostream>
#include <vector>

int main() {
const int N = 1000000;

std::vector<int> v1;
v1.reserve(N);
for (int i = 0; i < N; ++i) {
v1.push_back(i);
}

std::cout << v1.capacity() << " and size = " << v1.size() << std::endl;

for (int i = 0; i < N - 2; ++i) {
v1.pop_back();
}

std::cout << v1.capacity() << " and size = " << v1.size() << std::endl;

return 0;
}

Выход:

1000000 and size = 1000000
1000000 and size = 2

где capacity явно не уменьшается.

[РЕДАКТИРОВАТЬ]

Еще один актуальный вопрос, который также может быть помечен как дубликат, имеет несколько хороших ответов. Вот несколько интересных:

1)

Посмотрите на пункт 17 «Эффективный STL» Скотта Мейерса.
По сути, вы не можете напрямую уменьшить размер хранилища std :: vector. «Хитрость» заключается в том, чтобы> создать новый контейнер нужного размера, скопировать данные и заменить их текущим контейнером.

2)

Нет, вы не можете уменьшить емкость вектора без копирования.

3)

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

Я предлагаю прочитать ссылку для более.

[EDIT.2]

это вопрос также поддерживает это:

Q: может pop_back() когда-либо уменьшить capacity?

A: НЕТ.

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

5

Комментарии на самом деле не обращаются к этому. Ясно, что если в std :: vector запрещено использовать что-либо, кроме std :: allocator, и если std :: allocator запрещено расширять дополнительными методами, то изменение размера с тем же базовым адресом невозможно, что делает невозможным уменьшение емкости, поскольку итераторы будут признаны недействительными.

Самая близкая информация, которую я мог найти о перераспределении, была комментарием стека переполнения Почему в распределителях C ++ нет функции перераспределения? поговорка

«Ничто не мешает std :: vector делать это в некоторых случаях (например, он знает, что использует стандартный распределитель). Стандартной библиотеке разрешено использовать знания базовой системы. — KeithB Jun 23 ’10 в 21:39 «(хотя ссылки не упоминаются)

Были представлены идеи по добавлению realloc в std :: allocator, но оба они были отклонены:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1953.html

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2045.html

В документах прямо не указывается, что std :: allocator запрещено расширять std :: allocator, хотя они только утверждают, что в этом нет необходимости. Они также явно не заявляют, что std :: vector запрещено использовать вызовы API для базовой системы … Так что никакой реальной информации там тоже нет.

1