像迭代器一样编写 STL

Writing STL like iterator

本文关键字:一样 STL 迭代器      更新时间:2023-10-16

我试图学习像迭代器一样编写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;
}

当我编译不起作用的部分时,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]

作品部分无缝编译,当编译时没有不工作部分。有人可以解释我出了什么问题吗?

我认为问题出在这些方面:

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

这里的问题是这些函数接受对其参数的左值引用。 这意味着,如果尝试将右值(例如,从函数返回的临时对象)传递给这些运算符,则会收到编译时错误,因为引用无法绑定到临时运算符。 要解决此问题,请将参数更改为常量引用:

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

由于 const 引用可以绑定到临时引用,或者让它们按值获取参数:

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

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

希望这有帮助!

#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 标记 ;)

为自定义容器编写迭代器时,您可能会发现使用 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指定迭代器遍历 - 这意味着您只能使用迭代器沿正向遍历容器,并且一次只能单步执行一个元素。