I have a class with a std::vector<int> member and a member function returning a const reference to that vector.
class demo {
public:
//...
const std::vector<int> & test() const {
return iv;
}
private:
std::vector<int> iv;
};
I plan to change the member type to a different array like container type with just enough functionality and a smaller memory footprint (e.g. std::experimental::dynarray, std::unique_ptr<int[]>). Therefore I thought it would be a good idea to not return the real container as a const reference but to return a view to the elements as a gsl::span<const int>.
class demo {
public:
//...
gsl::span<const int> test() const {
return iv;
}
private:
std::vector<int> iv;
};
But this breaks code that worked with the const vector<int>& because two span instances of the same unmodified vector can't be used to iterate over the elements:
demo d;
std::cout << (d.test().begin() == d.test().begin()) << "\n";
std::cout << (d.test().end() == d.test().end()) << "\n";
for( auto it = d.test().begin(), end = d.test().end(); it != end; ++it )
std::cout << *it << "\n";
This prints 0 0 and then crashes because the test it != end never fails. A range based for loop works of course, but this loop is valid and therefore must also work as expected. I had expected, that all spans from the same range of the same container are equal so that iterators of any of these spans are comparable (container not modified of course). Certainly there is a good reason why this isn't so.
So my question is, what is the best way to return such a view to elements of a array like container whose type should not be visible to the caller.
You use iterator
of temporary, so your iterator
become invalided directly after affectation.
You may use the following:
auto&& view = d.test();
for (auto it = view.begin(), end = view.end(); it != end; ++it) {
std::cout << *it << "\n";
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With