Рассмотрим эту гипотетическую реализацию vector
:
template<class T> // ignore the allocator
struct vector
{
typedef T* iterator;
typedef const T* const_iterator;
template<class It>
void insert(iterator where, It begin, It end)
{
...
}
...
}
Проблема
Здесь мы сталкиваемся с тонкой проблемой:
существует вероятность того, что begin
и end
ссылаются на элементы в одном и том же векторе, после where
.
Например, если пользователь говорит:
vector<int> items;
for (int i = 0; i < 1000; i++)
items.push_back(i);
items.insert(items.begin(), items.end() - 2, items.end() - 1);
Если It
не является типом указателя, то все в порядке.
Но мы не знаем, поэтому мы должны проверить, что [begin, end)
не относится к диапазону, уже находящемуся внутри вектора.
Но как мы это делаем? Согласно C++, если они не ссылаются на один и тот же массив, то сравнение указателей будет неопределенным!
Таким образом, компилятор может ложно сообщить нам, что элементы не являются псевдонимами, хотя на самом деле они это делают, что приводит к ненужному замедлению на O(n).
Возможное решение и предостережение
Одним из решений является копирование полного вектора каждый раз, чтобы включить новые элементы, а затем выбросить старую копию.
Но это очень медленно в таких сценариях, как в приведенном выше примере, где мы копируем 1000 элементов только для того, чтобы вставить 1 элемент, даже если у нас уже может быть достаточно места.
std::less
и т. д., которые гарантированно дадут общий порядок, даже если сравнение необработанных указателей этого не сделает. - person Mankarse   schedule 20.08.2012vector
s, определенные в стандарте, имеют неопределенное поведение, если вы попытаетесь сделать это, потому что итераторы становятся недействительнымиinsert
. (Не препятствовать реализации, которая расширяет/изменяетstd::vector
для поддержки этого). - person Mankarse   schedule 20.08.2012less(p1, p2)
не занимается УБ, аp1 < p2
занимается?? Я этого не знал! - person user541686   schedule 20.08.2012[comparisons]/8: For templates greater, less, greater_equal, and less_equal, the specializations for any pointer type yield a total order, even if the built-in operators <, >, <=, >= do not.
- person Mankarse   schedule 20.08.2012if
. Почему вы все время страдаете от замедления O(n)? - person David   schedule 20.08.2012if
работает некорректно. - person user541686   schedule 20.08.2012if
реализацией. - person David   schedule 20.08.2012std::rotate
, верно? - person user541686   schedule 20.08.2012std::rotate
в основном представляет собой цикл свопов, верно? Я никогда не использовал его. Но на самом делеstd::rotate_copy
может быть вся логика подкачки, которую я описал, уже написанная для вас. - person David   schedule 20.08.2012