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

Вставляет ли элемент std::vector в тот же вектор?

Рассмотрим следующие insert и emplace функции-члены std::vector<T>:

template <class... Args> iterator emplace(const_iterator position, Args&&... args);
iterator insert(const_iterator position, const T& x);
iterator insert(const_iterator position, T&& x);
iterator insert(const_iterator position, size_type n, const T& x);

Что делать, если один из них вызывается с ссылкой на элемент самого вектора в качестве аргумента? Обычно каждый из них делает недействительными ссылки на все элементы, начиная с position, которые могут включать аргумент, или если происходит перераспределение, ссылки на все элементы, которые определенно включают его, но означает ли это, что такой вызов недействителен или сначала появляются вставки (кажется)?

Взгляд на некоторые общие реализации дает любопытные результаты:

  • libstdС++ копирует аргумент перед перемещением любых элементов, но только в const T& перегрузках insert. Он содержит этот комментарий:

    Порядок трех операций продиктован С++ 0x случай, когда ходы могут изменить новый элемент, принадлежащий к существующему вектору. Это проблема только для абонентов взяв элемент по const lvalue ref (см. 23.1/13).

    Но С++ 11 §23.1 - это всего лишь краткое изложение библиотеки контейнеров, и даже если мы предполагаем, что это относится к § 23.2.1 (который использовался в §23.1 в С++ 03), §23.2.1/13 дает только определение контейнеров, поддерживающих распределители, которые, похоже, не имеют к этому никакого отношения. Ive просмотрел главу 23, но я ничего не нашел в любом месте.

  • libС++ создает временный объект перед перемещением любых элементов в emplace, а в insert он сначала перемещает элементы, но преобразует ссылку аргумента в указатель и настраивает его, чтобы убедиться, что он указывает на исходный элемент, - но снова, он делает все это только в перегрузке const T&.

  • Visual С++ создает копию/временную информацию перед перемещением любых элементов во всех случаях.

Пропустил ли я место, где стандарт определяет это поведение? Почему три библиотеки С++, на которые я смотрел, не согласны друг с другом? Почему комментарий libstdС++ говорит о своей единственной проблеме для insert(const_iterator, const T&)? Если стандарт не требует, чтобы это работало, почему библиотеки когда-либо пытались заставить его работать вообще? (Разумеется, это требует некоторых копий и/или ходов, которые в противном случае можно было бы избежать.) Наконец, если Im реализует контейнер, который должен напоминать std::vector, должен ли я сделать эту работу?

4b9b3361

Ответ 1

Сначала ответьте на второй вопрос: стандарт явно говорит, что стандартной библиотеке разрешено предполагать, что при передаче чего-либо ссылкой rvalue эта ссылка rvalue является единственной ссылкой на этот объект. Это означает, что он не может юридически быть элементом вектора. Соответствующая часть С++ 11 17.6.4.9/1:

  • Если аргумент функции связывается с параметром ссылки rvalue, реализация может предполагать, что этот параметр является уникальной ссылкой на этот аргумент.... [Примечание: если программа передает значение l xvalue при передаче этого lvalue в библиотечную функцию (например, вызывая функцию с аргументом move(x)), программа эффективно запрашивает эту функцию для обработки этого lvalue как временного. реализация может свободно оптимизировать пропуски наложения псевдонимов, которые могут потребоваться, если аргумент был lvalue. -end note]

Это дает нам возможность обрабатывать случай const T &. И хотя libstdС++ и libС++ отличаются в этом случае, их итоговый результат является одним и тем же - они корректно копируют из переданного объекта. И стандарт только предписывает поведение, а не реализацию. Пока они достигают правильного поведения, они в порядке.