Does container.clear() освобождает/перераспределяет внутренние буферы?

Если у меня есть контейнер и вызывается clear() на нем, это просто разрушает все элементы внутри или действительно ли освобождает/выделяет новую память внутри? Это поведение выходит за рамки стандарта С++?

Это сводится к:

unordered_set<int> mySet { 1, 2, 3, 4, 5 };
mySet.reserve(1000);
mySet.clear();

//Is this pointless/redundant
//or should I treat my container like it was just constructed?
mySet.reserve(1000);

Быстрый тест на ideone (http://ideone.com/XQi8IT) показывает, что буфер внутренней памяти сохраняется после вызова для очистки. Итак, по крайней мере, для новых версий g++ на unordered_set это так. Мой вопрос касается 1) того, что стандарт говорит, если что-либо и 2) является ли это поведение согласованным во всех контейнерах.

Ответ 1

Не указано, что происходит с памятью. Он просто определяет следующие требования:

В контейнерах с последовательностями для clear() имеются следующие требования:

[C++11 §23.2.3] Таблица 100

Уничтожает все элементы в a. Недействительность всех ссылок, указателей, итераторы, ссылающиеся на элементы a и могут аннулировать прошлый итератор.

post: a.empty() возвращает true

Что на самом деле ничего не говорит о памяти. Для ассоциированных контейнеров мы имеем это требование для clear():

[C++11 §23.2.4] Таблица 102

a.erase(a.begin(),a.end())

Что приводит к требованиям erase(...), которые:

стирает элемент, на который указывает q. Возвращает итератор, указывающий на элемент, следующий за q до стирания элемента. Если такой элемент не существует, возвращает a.end()

Что опять же не упоминает о емкости буфера памяти контейнера. Тогда у нас есть неупорядоченные ассоциированные контейнеры, которые имеют схожие формулировки:

[C++11 §23.2.5] Таблица 103

Стирает все элементы в контейнере. Сообщение: a.empty() возвращает true

В целом, стандарт не упоминает, что что-то происходит с буферами внутренней памяти после clear. Таким образом, неопределенное поведение, которое может варьироваться между различными реализациями.

Так как reserve недоступен во всех контейнерах (что меняет емкость), и ни одна из них не является следующей лучшей (shrink_to_fit), похоже, нет хорошего способа последовательно очищать внутреннюю память контейнер.

Ответ 2

В стандарте С++ нет требования для любого стандартного контейнера для освобождения памяти. Даже функция std::vector<T>::shrink_to_fit() запрашивает только сокращение памяти. Считается, что эта функция заменяет идиомы типа

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

Эта идиома использовалась для действительно свободной памяти, что не гарантируется std::vector<T>::clear(). (Фактически, std::vector<T>::clear() указывается, чтобы оставить capacity() неизменным.) Вы все равно можете использовать эту идиому для других контейнеров, хотя они не имеют функции shrink_to_fit().