Reputation: 1292
Put it other way, conversely, are std::span
iterators invalidated after the span instance is destroyed?
I have a vector I need to iterate over with different layouts. I'm trying to make use of std::span
to avoid writing a lot of iterator boilerplate or bringing in an external library dependency. Simplified example:
#include <iostream>
#include <span>
#include <vector>
template <size_t N>
struct my_view {
std::vector<int> vec;
auto as_span() {
return std::span<int[N]>((int(*)[N])vec.data(), vec.size() / N);
}
auto begin() {
return as_span().begin();
}
auto end() {
return as_span().end();
}
};
int main() {
std::vector vec {1, 2, 3, 4, 5, 6};
my_view<2> pairs {std::move(vec)};
for (auto pair : pairs) {
std::cout << pair[0] << " " << pair[1] << std::endl;
}
my_view<3> triplets {std::move(pairs.vec)};
for (auto triplet : triplets) {
std::cout << triplet[0] << " " << triplet[1] << " " << triplet[2] << std::endl;
}
return 0;
}
https://godbolt.org/z/n1djETane
Upvotes: 5
Views: 816
Reputation: 303057
I appreciate that this question asks both the positive and negative version of the same question consecutively. Thus...
Can
std::span
iterators outlive the span object they are created from?
Yes.
Are
std::span
iterators invalidated after the span instance is destroyed?
No.
This is why you in [span.syn] you see:
template<class ElementType, size_t Extent>
inline constexpr bool ranges::enable_borrowed_range<span<ElementType, Extent>> = true;
Where, from [range.range]/5:
Given an expression
E
such thatdecltype((E))
isT
,T
modelsborrowed_range
only if the validity of iterators obtained from the object denoted byE
is not tied to the lifetime of that object.
[Note 2: Since the validity of iterators is not tied to the lifetime of an object whose type models
borrowed_range
, a function can accept arguments of such a type by value and return iterators obtained from it without danger of dangling. — end note]
Were a span
's iterators to be tied to the lifetime of the span
, it would be invalid to do this -- span
would have to be non-borrowed (as, e.g., vector<T>
clearly is not borrowed).
gsl::span
's iterators used to keep a pointer to the span
(which would obviously cause the iterators to be invalidated), but that was changed in Feb 2020 (I have not looked through the comments to find the discussion there, but that one matches the standard behavior).
Upvotes: 6