Что произойдет, если я использую 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 на вектор.