Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should I return gsl::span<const T> instead of const std::vector<T>&

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.

like image 490
Stefan F. Avatar asked Nov 23 '16 13:11

Stefan F.


1 Answers

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";
}
like image 85
Jarod42 Avatar answered Nov 03 '22 20:11

Jarod42