Почему добавление объекта std::deque к себе через std::copy успешно, если deque недостаточно велик?

Книга права, я просто неправильно прочитал строку.

Как ясно указывает ответ @uneven_mark, следующий вопрос зависит от моего неправильного прочтения.

Читая Стандартную библиотеку C++ (2-е издание) Джосуттиса, я как-то убедился в том, что coll на странице 457 объявлен как std::deque (наоборот, он объявлен как std::list!), следовательно, я задал этот вопрос.

Я надеюсь, что это может послужить пищей для размышлений для читателей.

ОРИГИНАЛЬНЫЙ ВОПРОС:

На странице 456 "Стандартной библиотеки C++ (2-е издание)" Джозуттис отмечает, что перед тем, как позвонить вам

copy(coll.begin(), coll.end(), back_inserter(coll));

на coll класса std::vector, вы должны убедиться, что coll имеет достаточно места (в этом случае, что он имеет capacity по крайней мере, в два раза size), в противном случае

алгоритм аннулирует переданные исходные итераторы во время работы.

Напротив, на странице 458 он не говорит ничего подобного для случая

copy(coll.begin(), coll.end(), front_inserter(coll));

применительно к coll класса std::deque хотя на странице 286 указано следующее std::deque контейнер:

[...] когда элементы вставляются спереди или сзади. В этом случае ссылки и указатели на элементы остаются действительными, а итераторы - нет.

отсюда мое сомнение. (Да, я знаю std::deque даже не предлагает reserve -подобная функция-член.)

Пока я понял этот ответ, я понимаю, что front_inserter(coll) итератор может вызвать перераспределение массива указателей (что является законным способом реализации std::deque), и не может вызвать перераспределение массивов, в которых coll сохраняются, таким образом, оставляя ссылки / указатели на элементы действительными, в то же время аннулируя iterator ы, чье правильное поведение (я думаю о том, как operator++ может быть реализовано) опирается как на массив указателей, так и на указатели на массивы.

Если это правда, то я предполагаю, что параметр, соответствующий copy аргумент coll.begin() становится недействительным в тот момент, когда присвоение ему вызывает перераспределение массива указателей.

1 ответ

Решение

Страница 455/456 книги представляет std::back_inserterв то время как страница 457/458 вводит std::front_insert, В каждом случае есть краткое объяснение, включая список применимых контейнеров. Каждый раздел имеет фрагмент кода в качестве примера, и только один из применимых контейнеров выбран для иллюстрации использования.

За std::back_inserterкак контейнер std::vector выбирается и комментарий в фрагменте кода упоминает, почему необходимо сначала зарезервировать достаточно места в векторе.

За std::front_inserter автор выбрал std::listне std::deque, std::list не делает недействительными ссылки или итераторы при вставке, поэтому

copy(coll.begin(), coll.end(), front_inserter(coll));

в порядке, см. [list.modifiers]:

Примечания: не влияет на достоверность итераторов и ссылок. Если выброшено исключение, никаких эффектов нет.

Поэтому в обоих случаях нет ошибки в авторском коде. Я полагаю, что он никогда не намеревался полностью объяснить опасность копирования в сам контейнер, а просто выбрал эти случаи, потому что это позволило ему написать более короткие полные примеры использования.

Я думаю для случая, когда coll это std::deque это явно неопределенное поведение. std::front_inserter вставляет элементы по вызовам push_front [front.insert.iter.ops]

Эффекты: Как будто by: container->push_front (value);

, который делает недействительными все итераторы [deque.modifiers]:

Эффекты: вставка в середине deque делает недействительными все итераторы и ссылки на элементы deque. Вставка в любом конце deque делает недействительными все итераторы в deque, но не влияет на достоверность ссылок на элементы deque.

В то же время std::copys поведение [alg.copy]:

Эффекты: копирует элементы из диапазона [first, last) в диапазон [result, result + N), начиная с первого и заканчивая последним. Для каждого неотрицательного целого числа n

После первой вставки first является недействительным, и будет вызвано неопределенное поведение.

Другие вопросы по тегам