Что произойдет, если я использую vector::begin() вместо std::back inserter(vector) для вывода пересечения множества?

я использую очень краткий и интуитивно понятный синтаксис C++ для поиска пересечения двух отсортированных vectors и положить результат в третьем vector:

vector<bar> a,b,c;
//...
std::set_intersection(a.begin(),a.end(),b.begin(),b.end(),
                      std::back_inserter(c));

это должно установить c до перекрестка(a,b), полагая a и b сортируются.

но что, если я просто использовать c.begin() (мне показалось, что я где-то видел пример этого, поэтому я и сделал):

 std::set_intersection(a.begin(),a.end(),b.begin(),b.end(),
                       c.begin());

set_intersection ждет OutputIterator при этом параметр. Стандарт, который я считаю, требует только этого c.begin() возвратить forward iterator, который, я полагаю, может быть или не быть OutputIterator.

в любом случае, код c.begin() скомпилировано под clang.

что гарантировано для того чтобы случиться под стандартом? Если это компилируется, что, скорее всего, произойдет - то есть, когда итератор возвращается c.begin() в конечном итоге увеличивается за конец вектора, и делается попытка получить доступ к элементу, на который указывает, что должно/может случится? Может ли соответствующая реализация молча расширить вектор в этом случае, так что begin() на самом деле является приложением OutputIterator как back_inserter - это?

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

3 ответов


важным требованием для выходного итератора является его допустимость и возможность записи для диапазона
[out, out+размер).

передает c.begin() приведет к значениям перезаписаны который работает только если контейнер c содержит достаточно элементов для перезаписи. Представь, что c.begin() возвращает указатель на массив размером 0-тогда вы увидите проблему при написании *out++ = 7;.

back_inserter добавляет каждое присвоенное значение a vector (via push_back) и предоставляет краткий способ сделать STL-алгоритмы расширяют диапазон - он перегружает операторы, которые используются для итераторов соответствующим образом.

 std::set_intersection(a.begin(),a.end(),b.begin(),b.end(),
                       c.begin());

вызывает неопределенное поведение после set_intersection записывает что-то в свой выходной итератор, то есть когда задано пересечение a и b не пуста.

может соответствовать реализация молча расширяет вектор в этом случае, так что begin () фактически является добавлением OutputIterator как back_inserter - это?

конечно. Это неопределенное поведение. (Это юмористический подход, говорящий вам, что вы даже не должны рассматривать возможность использования этого, независимо от последствий для любой реализации.)


back_inserter вставляет элемент в диапазон, вызывая push_back ( вот почему вы не можете использовать back_inserter с диапазоном, который не обеспечивает push_back операции).

и вы не заботитесь о пройдя мимо конца диапазона как push_back автоматически расширяет контейнер. Однако это не относится к insert using begin().

если вы используете begin(), то вы должны убедиться, что диапазон назначения достаточно большой провести все элементы. Неспособность сделать это мгновенно перенесет ваш код в область неопределенного поведения.


он компилируется отлично, потому что вы получаете действительный итератор из begin функция, но если вектор пуст, то вы получите обратно end итератор, а затем продолжить оттуда.

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

и добавление элементов-это то, что back_inserter итератор делает, он возвращает итератор, который в основном делает push_back на вектор.