5

I am making my own implementation of Vector in C++. This is a two part question.

Part 1: When attempting to iterate through a Vector, my begin() and end() iterators are unable to handle the input arguments. Below is my entire Vector.h implementation:

    class iterator{
    public:

        typedef std::random_access_iterator_tag iterator_category;
        typedef T value_type;

        Vector<T>* ptr;
        uint64_t position;
        COMLINK slave;

        void init(void){
            ptr = nullptr;
            position = 0;
        }
        void copy(const iterator& i){
            init();
            ptr = i.ptr;
            position = i.position;
            slave = i.slave;
        }
        void move(iterator&& i){
            init();
            std::swap(ptr, i.ptr);
            std::swap(position, i.position);
            std::swap(slave, i.slave);
        }

        iterator(void){
            init();
        }
        iterator(const iterator& q){
            copy(q);
        }
        explicit iterator(Vector<T>* v, uint64_t offset){
            init();
            ptr = v;
            position = offset;
            slave = v->master;
        }
        T& operator*(void){
            if ((position >= ptr->len) || ((ptr->buffer + position) < ptr->elem))throw invalid_iterator(invalid_iterator::SEVERE);
            else if (slave.move_cnt != ptr->master.move_cnt) throw invalid_iterator(invalid_iterator::MODERATE);
            else if (slave.alter_cnt != ptr->master.alter_cnt) throw invalid_iterator(invalid_iterator::MILD);
            else if (slave.position_cnt != ptr->master.position_cnt) throw invalid_iterator(invalid_iterator::WARNING);
            return *(ptr->elem + position);
        }
        bool operator==(const iterator& rhs){
            return (ptr == rhs.ptr) && (position == rhs.position) && (slave == rhs.slave);
        }
        bool operator!=(const iterator& rhs){
            return !((*this) == rhs);
        }
        iterator& operator=(const iterator& rhs){
            copy(rhs);
            return *this;
        }
        iterator& operator++(void){
            position++;
            return *this;
        }
        iterator& operator--(void){
            position--;
            return *this;
        }
        iterator operator+(uint64_t i){ // p + i
            iterator temp(*this);
            temp.position += i;
            return temp;
        }
        iterator operator-(uint64_t i){ // p - i
            iterator temp(*this);
            temp.position -= i;
            return temp;
        }
        uint64_t operator-(const iterator& q){
            return position - q.position;
        }
    };

    class const_iterator : public iterator {
    public:
        Vector<T>* const ptr;

        void init(void){
            ptr = nullptr;
            position = 0;
        }
        void copy(const_iterator& i){
            init();
            ptr = i.ptr;
            position = i.position;
            slave = i.slave;
        }
        void copy(iterator& i){
            init();
            ptr = i.ptr;
            position = i.position;
            slave = i.slave;
        }
        void move(const_iterator&& i){
            init();
            std::swap(ptr, i.ptr);
            std::swap(position, i.position);
            std::swap(slave, i.slave);
        }
        void move(iterator&& i){
            init();
            std::swap(ptr, i.ptr);
            std::swap(position, i.position);
            std::swap(slave, i.slave);
        }

        const_iterator(void){
            init();
        }
        const_iterator(const_iterator& i){
            copy(i);
        }
        explicit const_iterator(Vector<T>* const v, uint64_t offset){
            init();
            ptr = v;
            position = offset;
            slave = v->master;
        }
        const_iterator(iterator& i){
            copy(i);
        }
        const T& operator*(void){
            if ((position >= ptr->len) || ((ptr->buffer + position) < ptr->elem))throw invalid_iterator(invalid_iterator::SEVERE);
            else if (slave.move_cnt != ptr->master.move_cnt) throw invalid_iterator(invalid_iterator::MODERATE);
            else if (slave.alter_cnt != ptr->master.alter_cnt) throw invalid_iterator(invalid_iterator::MILD);
            else if (slave.position_cnt != ptr->master.position_cnt) throw invalid_iterator(invalid_iterator::WARNING);
            return *(ptr->elem + position);
        }
        const_iterator& operator=(iterator& i){
            copy(i);
            return *this;
        }
    };

And these are the beign() and end() functions in vector:

    iterator& begin(){
        return iterator(this, 0);
    }

    const_iterator& begin() const{
        return const_iterator(this, 0);
    }

    iterator& end(){
        return iterator(this, len);
    }

    const_iterator& end() const{
        return const_iterator(this, len);
    }

And... finally (sorry for length) ... here is the test code triggering the compile error:

const Vector<int32_t>& y = x;
int32_t s = 0;
for (const auto& v : y) {
    s += v;
}

The error I receive is:

Warning 3   warning C4172: returning address of local variable or temporary c:\users\alexander\documents\visual studio 2013\projects\vectorcontainerphasec_debug\vector.h   319 1   VectorContainerPhaseC_Debug
Error   4   error C2665: 'epl::Vector<int>::const_iterator::const_iterator' : none of the 4 overloads could convert all the argument types  c:\users\alexander\documents\visual studio 2013\projects\vectorcontainerphasec_debug\vector.h   323 1   VectorContainerPhaseC_Debug

I have been researching this issue for hours and can't find a solution. Any tips?

Part 2: Is there another way to implement const_iterator than I have done above? It seems redundant for me to redefine so many functions from iterator to const_iterator. Do I even need to create a const_iterator class?

alex
  • 65
  • 1
  • 6
  • You have a `const` object and you're trying to pass a pointer to it into something taking a pointer to a non-const object. – chris Feb 23 '14 at 06:04
  • Why do your `begin` and `end` functions return by reference? – jogojapan Feb 23 '14 at 06:09
  • I think your issue is wherever you have `Vector* const`: I think what you need is actually `const Vector *`. The first one says "constant pointer to Vector" whereas the second says "pointer to Vector constant" (or alternatively "pointer to constant Vector). More generally, if you have `const T * p`, then you can change _what_ `p` is pointing _to_, but not modify that value (cannot modify `*p`; if you have `T * const q`, then you _cannot_ change what `q` points at, but you _can_ change that value (kind of like a reference). – Nicu Stiurca Feb 23 '14 at 06:19
  • Having `const_iterator` derive from `iterator` seems wrong to me, that means a const_iterator is implicitly convertible to an iterator. Besides, you end up with two `ptr` in your object. You are missing a number of typedef and functions to make this a valid iterator. Boost has helpers to create iterators without writing so much repetitive stuff yourself. – Marc Glisse Feb 23 '14 at 08:06
  • About the warning C4172: Your `begin` and `end` methods return dangling references. Get rid of the `&` and return by value. – fredoverflow Feb 23 '14 at 09:57
  • Thanks all! This has been very helpful – alex Feb 23 '14 at 14:05

1 Answers1

3

You probably want your const_iterator to point to a const Vector. You also need to adjust your constructor, like follows:

class const_iterator : public iterator {
public:
    const Vector<T>* const ptr;

    ...
    explicit const_iterator(const Vector<T>* v, uint64_t offset){
        ...
    }

That way, your const_iterator constructor should be callable within your range for iteration.
See Difference between const declarations in C++ if you need to understand the details of how the const keyword works in pointer declarations.

Community
  • 1
  • 1
Martin J.
  • 5,028
  • 4
  • 24
  • 41