Я написал класс для использования его в качестве удобного представления, например, в for
s на основе диапазона. В целом, это всего лишь пара итераторов с проверкой привязки:
template<typename I> class Range {
private:
I begin;
I end;
public:
Range(I const begin, I const end)
: begin(begin), end(end)
{}
Range<I>& skip(int const amount) {
begin = std::min(begin + amount, end);
return *this;
}
};
template<typename C> auto whole(C const& container) {
using Iterator = decltype(std::begin(container));
return Range<Iterator>(std::begin(container), std::end(container));
}
Вот его предполагаемое использование (которое привело к UB):
std::vector<int> const vector{1, 2, 3};
for (int const value : whole(vector).skip(1)) {
std::cout << value << ' ';
}
Удаление части skip(1)
помогает, то же самое касается следующего рефакторинга Range::skip
:
Range<I> skip(int const amount) const {
I const new_begin = std::min(begin + amount, end);
return Range<I>(new_begin, end);
}
Похоже, временное не должно возвращать ссылку на себя. Вот что говорит cppreference:
Все временные объекты уничтожаются на последнем этапе оценки полного выражения, которое (лексически) содержит точку, в которой они были созданы, и если было создано несколько временных объектов, они уничтожаются в порядке, противоположном порядку создания.
Хотя я не уверен, что это так, и я не знаю, как интерпретировать это практически. В чем реальная проблема и как я могу надежно избежать такого UB? Подобные выражения, например auto string = std::string("abc").append("def")
, тоже небезопасны?