编写类似STL迭代器的代码

4

我尝试学习编写像迭代器一样的stl,为此我编写了一个简单的循环数组并在其中添加了一个迭代器。请查看代码底部以查看问题。

template<typename T, int N>
class RingQueue{
    T * _marray;
    int _mbegin;
    int _msize;
public:
    RingQueue(){
        _marray = new T[N];
        _mbegin = 0;
        _msize= 0;
    }   
    void push_back(const T& val){
        if(_msize!=N){
            _marray[(_mbegin+_msize)%N] = val;
            _msize++;
        }
        else
            throw "Queue Full";
    }   
    T pop_front(){
        if(_msize!=0){
            T&val = _marray[_mbegin];
            _mbegin = (_mbegin+1)%N;
            _msize--;
            return val;
        }
        else
            throw "Queue Empty";
    }

    class iterator{
        RingQueue<T,N>* _container;
        int _idx;
        public:
        iterator(RingQueue<T,N>* container,int idx):_container(container){
            _idx = idx;
        }

        bool operator==(iterator &rhs){
            return (this->_container==rhs._container && this->_idx == rhs._idx);
        }
        bool operator!=(iterator &rhs){
            return !(*this==rhs);
        }   
        T operator*(){
            if(_container->_msize>0&&_idx<_container->_msize){
                return _container->_marray[(_container->_mbegin+_idx)%N];
            }
        }

        iterator& operator++(){
            if(_container->_msize ==0){
                *this = _container->end();
                return *this;
            }
            if(_idx==_container->_msize){   
                *this = _container->end();
                return *this;
            }
            _idx++;
            return *this;
        }
    };
    iterator begin(){
        return iterator(this,0);
    }
    iterator end(){
        return iterator(this,_msize);
    }
};
int current=0;
int gen(){
    return current++;
}

int curr_op=0;
int operation(){
    return 2*(curr_op++&1)-1;
}
int main(){
    RingQueue<int,10> ring;
    vector<int> v(9),op(9);
    generate(v.begin(),v.end(),gen);
    random_shuffle(v.begin(),v.end());
    copy(v.begin(),v.end(),ostream_iterator<int>(cout," "));    
    cout<<endl;

    generate(op.begin(),op.end(),operation);        
    random_shuffle(op.begin(),op.end());
    // copy(op.begin(),op.end(),ostream_iterator<int>(cout," "));   
    cout<<endl;

    for(vector<int>::iterator itv  = v.begin();itv!=v.end();itv++){
        try{
            ring.push_back(*itv);   
        }catch(const char * e){
            cout<<*itv<<e<<endl;
        }
    }
    //works
    RingQueue<int,10>::iterator ite = ring.end();
    for(RingQueue<int,10>::iterator it = ring.begin(); it!=ite; ++it){
        cout<<*it<<endl;
    }
    // doesn't work 
    for(RingQueue<int,10>::iterator it = ring.begin(); it!=ring.end(); ++it){
        cout<<*it<<endl;
    }
    return 0;
}

当我编译“doesn't work”部分时,g++会抛出以下错误。
ringqueue.cpp: In function ‘int main()’:
ringqueue.cpp:112: error: no match for ‘operator!=’ in ‘it != ring.RingQueue<T, N>::end [with T = int, int N = 10]()’
ringqueue.cpp:48: note: candidates are: bool RingQueue<T, N>::iterator::operator!=(RingQueue<T, N>::iterator&) [with T = int, int N = 10]

当不编译doesn't work部分时,works部分可以顺利编译。有人能解释一下问题出在哪里吗?

3个回答

9
我认为问题出在这几行代码上:

我认为问题出在这几行代码上:

    bool operator==(iterator &rhs){
        return (this->_container==rhs._container && this->_idx == rhs._idx);
    }
    bool operator!=(iterator &rhs){
        return !(*this==rhs);
    }  

这里的问题在于这些函数使用左值引用作为它们参数的类型。这意味着,如果你试图将一个右值(例如从函数返回的临时对象)传递给这些运算符,你会遇到编译时错误,因为引用不能绑定到临时变量上。为了解决这个问题,可以将参数改为const引用:

    bool operator==(const iterator &rhs){
        return (this->_container==rhs._container && this->_idx == rhs._idx);
    }
    bool operator!=(const iterator &rhs){
        return !(*this==rhs);
    }  

由于常量引用可以绑定到临时对象,或者通过值传递参数:

    bool operator==(iterator rhs){
        return (this->_container==rhs._container && this->_idx == rhs._idx);
    }
    bool operator!=(iterator rhs){
        return !(*this==rhs);
    }  

无论您做出哪种选择,都应该将这些函数标记为const,因为它们不会改变接收对象。
希望这可以帮到您!

啊,我不应该错过那个问题,之前也遇到过类似的问题。非常感谢。还有一件事,你能解释一下错误信息吗?谢谢。 - HBY4PI

0
#include <vector>
#include <iostream>
#include <sstream>
#include <iterator>
using namespace std;

template<typename T, int N>
class RingQueue{
    T * _marray;
    int _mbegin;
    int _msize;
public:
    RingQueue(){
        _marray = new T[N];
        _mbegin = 0;
        _msize= 0;
    }   
    void push_back(const T& val){
        if(_msize!=N){
            _marray[(_mbegin+_msize)%N] = val;
            _msize++;
        }
        else
            throw "Queue Full";
    }   
    T pop_front(){
        if(_msize!=0){
            T&val = _marray[_mbegin];
            _mbegin = (_mbegin+1)%N;
            _msize--;
            return val;
        }
        else
            throw "Queue Empty";
    }

    class iterator{
        RingQueue<T,N>* _container;
        int _idx;
        public:
        iterator(RingQueue<T,N>* container,int idx):_container(container){
            _idx = idx;
        }

        bool operator==(iterator rhs){ // XXX do not pass it as a reference
            return (this->_container==rhs._container && this->_idx == rhs._idx);
        }
        bool operator!=(iterator rhs){ // XXX do not pass it as a reference
            return !(*this==rhs);
        }   
        T operator*(){
            if(_container->_msize>0&&_idx<_container->_msize){
                return _container->_marray[(_container->_mbegin+_idx)%N];
            }
            throw "XXX"; // XXX missing return statement
        }

        iterator& operator++(){
            if(_container->_msize ==0){
                *this = _container->end();
                return *this;
            }
            if(_idx==_container->_msize){   
                *this = _container->end();
                return *this;
            }
            _idx++;
            return *this;
        }
    };
    iterator begin(){
        return iterator(this,0);
    }
    iterator end(){
        return iterator(this,_msize);
    }
};
int current=0;
int gen(){
    return current++;
}

int curr_op=0;
int operation(){
    return 2*(curr_op++&1)-1;
}
int main(){
    RingQueue<int,10> ring;
    vector<int> v(9),op(9);
    generate(v.begin(),v.end(),gen);
    random_shuffle(v.begin(),v.end());
    copy(v.begin(),v.end(),ostream_iterator<int>(cout," "));    
    cout<<endl;

    generate(op.begin(),op.end(),operation);        
    random_shuffle(op.begin(),op.end());
    // copy(op.begin(),op.end(),ostream_iterator<int>(cout," "));   
    cout<<endl;

    for(vector<int>::iterator itv  = v.begin();itv!=v.end();itv++){
        try{
            ring.push_back(*itv);   
        }catch(const char * e){
            cout<<*itv<<e<<endl;
        }
    }
    for(RingQueue<int,10>::iterator it = ring.begin(); it!=ring.end(); ++it){
        cout<<*it<<endl;
    }
    return 0;
}

代码正常运行。请寻找XXX标记;)


通常应避免传递整个对象,这使得templatetypedef的答案更好。尽管如此,我也应该尝试一下你的方法。谢谢。 - HBY4PI
好的,我说过我的解决方案是有效的,并指出了问题所在。我从未说过那是最好的解决方案 ;) 但我也为templatetypedef投了赞成票 ;) - zmo

0

当为自定义容器编写迭代器时,您可能会发现使用boost::iterator_facade很有帮助。这是一个库,允许您仅定义迭代器的基本操作(增量、解引用和相等比较,以及如果适用,则为减量和提前)并通过提供所有必需的运算符来填补空白。以下是使用boost::iterator_facade定义迭代器的示例:

class iterator : public boost::iterator_facade<iterator, T, boost::forward_traversal_tag>{
    RingQueue<T,N>* _container;
    int _idx;
public:
    iterator(RingQueue<T,N>* container,int idx):_container(container){
        _idx = idx;
    }

    bool equal(const iterator &rhs) const {
        return (this->_container==rhs._container && this->_idx == rhs._idx);
    }

    T dereference() const {
        if(_container->_msize>0&&_idx<_container->_msize){
            return _container->_marray[(_container->_mbegin+_idx)%N];
        }
    }

    void increment(){
        if(_container->_msize ==0)
            *this = _container->end();
        else if(_idx==_container->_msize)
            *this = _container->end();
        else
            _idx++;
    }
};

boost::forward_traversal_tag指定了迭代器的遍历方式。这意味着你只能使用该迭代器沿着正向方向遍历容器,并且每次只能遍历一个元素。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接