Подтвердить что ты не робот

При сжатии контейнера с помощью изменения размера, в каком порядке уничтожаются элементы?

Если у меня есть стандартный контейнер С++ std::vector<Bar>, и я сокращаю его, вызывая .resize() с размером меньше текущего .size(), в каком порядке уничтожаются лишние элементы?

(Варианты выбора интересны, если вы можете найти две реализации, которые отличаются.)

(Это было вдохновлено комментарием Джеймсом Канзе.)

4b9b3361

Ответ 1

В соответствии с рабочим проектом января 2012 года

В рабочем проекте января 2012 года содержатся стандартные версии С++ 11 плюс незначительные редакционные изменения.

Источник, рабочий проект

Для vector:

void resize(size_type sz);
E ff ects: Если sz <= size(), эквивалентно erase(begin() + sz, end());. Если size() < sz, добавляет sz - size() значения-инициализированные элементы последовательности.

vector::erase не указывается порядок удаления. Я ожидаю, что он будет в порядке от begin() + sz до end(), потому что это имеет смысл для меня, но это только мое ожидание. Я не могу найти ничего об этом в стандарте.

Реализация vector, распространяемая вместе с Visual Studio 2013, действительно стирается в этом порядке, как и MinGW g++ 4.8.1, а также g++ 4.7.3 (не MinGW). Это компиляторы, к которым у меня есть легкий доступ.

В том же стандарте для list:

void resize(size_type sz);
1 E ff ects: Если size() < sz, добавляет sz - size() значения-инициализированные элементы в последовательность. Если sz <= size(), эквивалентное

list<T>::iterator it = begin();
advance(it, sz);
erase(it, end());

и

void resize(size_type sz, const T& c);
E ФФ ЕКТС:

if (sz > size())
    insert(end(), sz-size(), c);
else if (sz < size()) {
    iterator i = begin();
    advance(i, sz);
    erase(i, end());
}
else
    ; // do nothing

Затем далее указывается абсолютно ничего полезного о заказе для list::erase.

Реализация list, распространяемая с Visual Studio 2013, кажется, стирается в обратном порядке, в то время как MinGW g++ 4.8.1 и g++ 4.7.3 (не MinGW) этого не делают.

Основываясь на последнем рабочем черновике на момент написания

Рабочий проект

Для vector

void resize(size_type sz);
E ff ects: Если sz <= size(), эквивалентно вызову pop_back() size() - sz раз. Если size() < sz, добавляет sz - size() вставленные по умолчанию элементы в последовательность.

Это означает, что элементы удаляются в обратном порядке.

Для list:

void resize(size_type sz);
1 E ff ects: Если size() < sz, добавляет sz - size() значения-инициализированные элементы в последовательность. Если sz <= size(), эквивалентное

list<T>::iterator it = begin();
advance(it, sz);
erase(it, end());

и

void resize(size_type sz, const T& c);
E ФФ ЕКТС:

if (sz > size())
    insert(end(), sz-size(), c);
else if (sz < size()) {
    iterator i = begin();
    advance(i, sz);
    erase(i, end());
}
else
    ; // do nothing

Затем далее указывается абсолютно ничего полезного о заказе для list::erase.

Для deque стандарт определяет то же поведение, что и для vector.

Ответ 2

За исключением std::basic_string и std::forward_list, стандарт определяет resize в терминах erase (в случаях, когда новый размер меньше, чем оригинальный размер), поэтому вопрос действительно: erase( begin, end ) указать любой порядок уничтожения. И все, что я могу см. таблицу 100, в которой говорится, что erase( q1, q2 ) "Стирает элементы в диапазоне [q1, q2)". Который (для меня, при наименее) все еще оставляет открытым вопрос: когда стандарт использует обозначение [q1, q2) (где q1 и q2 - итераторы), означает ли это в порядке или нет? Априори, я бы не подумал. По крайней мере, в разделе <algorithms> он явно указывает когда операции должны быть в порядке (и тот факт, что это прямо указывает на это в некоторых конкретных случаях. что он не требуется в тех случаях, когда он не указан).

Для чего это стоит: для std::list<>::resize(), g++-вызовов удалять в порядке возрастания; VS в порядке убывания. В случае от VS, это отличается от порядка разрушения std::list<>::erase (что может быть законным, если порядок уничтожение не определено и разрешено варьироваться от одного вызова до следующий).

Ответ 3

Это зависит от контейнера. Например, эффект применения изменения размера к векторам следующий:

12 Effects: If sz <= size(), equivalent to calling pop_back() size() - sz times

Итак, для векторов порядок уничтожения элементов начинается с последнего элемента.

Для списков подход другой

Эффекты: Если size() < sz, добавляет элементы sz - size(), вставленные по умолчанию к последовательности. Если sz <= size(), эквивалентный списку:: iterator it = начать(); advance (it, sz); erase (it, end());

Но ничего не сказано, в каком порядке стираются элементы.