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

Использует ли std::vector:: swap аннулировать итераторы?

Если я поменяю два вектора, будут ли их итераторы оставаться в силе, теперь просто указывая на "другой" контейнер, или итератор будет недействителен?

То есть, данный:

using namespace std;
vector<int> x(42, 42);
vector<int> y;
vector<int>::iterator a = x.begin(); 
vector<int>::iterator b = x.end();

x.swap(y);

// a and b still valid? Pointing to x or y?

Кажется, std ничего не говорит об этом:

[n3092 - 23.3.6.2]

void swap(vector<T,Allocator>& x);

Эффекты: Обменивает содержимое и емкость() * этого с тем из x.

Обратите внимание, что поскольку я на VS 2005, я также заинтересован в эффектах проверки отладки итератора и т.д. (_SECURE_SCL)

4b9b3361

Ответ 1

Поведение swap значительно разъяснено в С++ 11, в значительной степени, чтобы позволить алгоритмам стандартной библиотеки использовать зависящий от зависимостей поиск (ADL) для поиска функций подкачки для пользовательских типов. С++ 11 добавляет концепцию swappable (С++ 11 §17.6.3.2 [swappable.requirements]), чтобы сделать это законным (и обязательным).

Текст в стандартном языке С++ 11, который отвечает на ваш вопрос, - это следующий текст из требований контейнера (§23.2.1 [container.requirements.general]/8), который определяет поведение swap член-функция контейнера:

Каждый итератор, ссылающийся на элемент в одном контейнере перед свопом, должен ссылаться на тот же элемент в другом контейнере после обмена.

Не указано, будет ли итератор со значением a.end() до того, как swap будет иметь значение b.end() после свопа.

В вашем примере гарантируется, что a будет действительным после обмена, но b не потому, что это итератор конца. Причина, по которой итераторы заканчиваются, не гарантируется, что они действительны, объясняется в примечании в §23.2.1/10:

[Примечание: итератор end() не ссылается ни на какой элемент, поэтому может быть аннулированной. - примечание]

Это то же поведение, которое определено в С++ 03, только что прояснено. Исходный язык от С++ 03 находится на С++ 03 §23.1/10:

Функция

no swap() делает недействительными любые ссылки, указатели или итераторы, ссылающиеся на элементы обменяемых контейнеров.

Это не сразу видно в исходном тексте, но фраза "элементам контейнеров" чрезвычайно важна, потому что итераторы end() не указывают на элементы.

Ответ 2

Обмен двумя векторами не отменяет итераторов, указателей и ссылок на его элементы (С++ 03, 23.1.11).

Обычно итератор будет содержать информацию о своем контейнере, а операция подкачки поддерживает это для данного итератора.

В VС++ 10 векторный контейнер управляется с использованием этой структуры в <xutility>, например:

struct _Container_proxy
{   // store head of iterator chain and back pointer
    _Container_proxy()
    : _Mycont(0), _Myfirstiter(0)
    {   // construct from pointers
    }

    const _Container_base12 *_Mycont;
    _Iterator_base12 *_Myfirstiter;
};

Ответ 4

Что касается Visual Studio 2005, я только что протестировал его. Я думаю, что он всегда должен работать, так как функция vector:: swap даже содержит явный шаг по замене всего:

 // vector-header
    void swap(_Myt& _Right)
        {   // exchange contents with _Right
        if (this->_Alval == _Right._Alval)
            {   // same allocator, swap control information

 #if _HAS_ITERATOR_DEBUGGING
            this->_Swap_all(_Right);
 #endif /* _HAS_ITERATOR_DEBUGGING */
 ...

Итераторы указывают на свои исходные элементы в векторном объекте с заменой теперь. (I.e.w/rg к OP, они сначала указывали на элементы в x, после свопинга они указывают на элементы в y.)

Обратите внимание, что в проекте n3092 требование изложено в п. 23.2.1/9:

Каждый итератор, ссылающийся на элемент в одном контейнере до подкачка относится к одному и тому же элементу в другом контейнере после обмена.