Antoine Morrier
Antoine Morrier

Reputation: 4078

Own iterator crashed with std::sort

I am trying to develop smart iterator, but even when I create a naive one it crash when I am using sort with it.

The range for loop worked well, but std::sort does not.

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

template<typename I>
class it {
public:
    it(I i) : i(i){}
    using iterator_category = std::random_access_iterator_tag;
    using value_type = typename I::value_type;
    using difference_type = std::ptrdiff_t;
    using pointer = typename I::pointer;
    using reference = typename I::reference;
    value_type &operator*() {
        return *i;
    }

    it &operator++() {
        ++i;
        return *this;
    }

    it &operator--() {
        --i;
        return *this;
    }

    bool operator!=(it a) {
        return a.i != i;
    }

    it &operator+(std::size_t n) {
        i += n;
        return *this;
    }

    it &operator-(std::size_t n) {
        i -= n;
        return *this;
    }

    std::ptrdiff_t operator-(it a) {
        return i - a.i;
    }

    bool operator==(it a) {
        return a.i == i;
    }

    bool operator<(it a) {
        return i < a.i;
    }

private:
    I i;
};

int main()
{
    std::vector<int> v = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0};

    for(auto e : v)
        std::cout << e << " ";
    std::cout << std::endl;

    std::sort(it<decltype(v.begin())>(v.begin()), it<decltype(v.end())>(v.end()));

    for(auto e : v)
        std::cout << e << " ";
    std::cout << std::endl;

    return 0;
}

The crash happen in "clang-code" here (gdb tell me that) :

struct _Iter_less_iter
  {
    template<typename _Iterator1, typename _Iterator2>
      _GLIBCXX14_CONSTEXPR
      bool
      operator()(_Iterator1 __it1, _Iterator2 __it2) const
      { return *__it1 < *__it2; }
  };

It happened when it deferrence it. Do you have an idea?

Upvotes: 0

Views: 89

Answers (2)

Benjamin Lindley
Benjamin Lindley

Reputation: 103713

Your operator+ has the semantics of operator+=, and your operator- has the semantics of operator-=. They should not modify the iterator, but instead create a new iterator with the modified value and return that. Also, they should both accept signed values. In fact, a proper random access iterator should have both sets of operators, so just keep the functions as they are, but change the signatures.

it& operator+=(difference_type n) {
    i += n;
    return *this;
}

it &operator-=(difference_type n) {
    i -= n;
    return *this;
}

Then you can implement operator+ and operator- in terms of those. (note that these return by value, not reference, and are marked const)

it operator+(difference_type n) const {
    it result = *this;
    result += n;
    return result;
}

it operator-(difference_type n) const {
    it result = *this;
    result -= n;
    return result;
}

Upvotes: 2

Pete Becker
Pete Becker

Reputation: 76370

Don't know for sure what the underlying problem is, but this is definitely wrong:

it &operator+(std::size_t n) {
        i += n;
        return *this;
    }

That operator should return a new iterator, and not modify the one it's called on. Something like this:

it operator+(std::size_t n) {
        it temp = *this;
        temp.i += n;
        return temp;
    }

Note that this returns the iterator by value, not by reference.

Same thing for operator-.

Upvotes: 3

Related Questions