Рассмотрим следующие 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
, должен ли я сделать эту работу?