Что произойдет, если я использую vector::begin() вместо std::back inserter(vector) для вывода пересечения множества?
я использую очень краткий и интуитивно понятный синтаксис C++ для поиска пересечения двух отсортированных vector
s и положить результат в третьем 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
на вектор.