C++11实现STL list以及内置迭代器

  1. 定义拷贝赋值 :多利用公共操作,这里拷贝赋值的实现中选择利用定义好的拷贝构造一个rhs的副本,然后swap(必须是三次移动),利用这个副本是本地变量,离开作用域后自动析构的原因,节省了代码量。
  2. 类里访问对象的私有成员 :一个对象的私有成员在类外是不能通过对象用.运算符访问的,但是在类内例外,即使像拷贝赋值,依然可以使用形参对象的私有成员。
  3. 将迭代器设置为(内嵌)类 :(在这里我浅显的理解以及书中原作者的理解)当我们只是将指针当成迭代器的时候,解引用和++(–)等操作可能发生错误(iterator可能已经冲过终点),当将其声明成一个类的时候,我们便可以将其运算符的操作重载,加入检验的语句,并在错误时抛出异常。 当然,还有其他优点:更加符合oop思想、可复用性和模块化。
  4. 迭代器将表指针作为类成员 :为防止对象进行erase和insert的时候,迭代器是指向该对象的,需要检验,就是在每个迭代器初始化时,要初始化指向对象的指针,通过这个指针来检验。
  5. 返回类型不能都是引用 :在begin()、end()这样的返回类型为迭代器的函数里,我们用tail(head)初始化了一个迭代器对象,但这个是一个右值,我们不能将左值引用(返回类型)绑定到一个右值上。也不能在函数体里返回一个局部变量的引用。
  6. 派生类访问基类成员 :虽然派生类继承了基类(派生类对象可以访问任何从基类继承来的protected、private成员),但是在派生类内访问基类成员需要用类作用域符显示地访问基类成员,或者用this指针访问,不能直接访问(编译器会报错:因为基类成员并没有声明在派生类里)。
  7. 总结:1. 尽量多用公共操作。 2. 每个函数的形参设置成为什么类型(能不能声明为常量或引用),都要根据上传的实参(左值、右值)类型确定,否则就要进行函数重载。所以,每个API的功能要提前构思好。
#include<algorithm>
#include<algorithm>
#include<iostream>
template<typename object>
class list{

private:
    struct node{
        object data;
        node * prev;
        node * next;
       

        node(const object & d = object{}, node * p = nullptr, node * n = nullptr) //构造函数
        :data(d), prev(p), next(n) {}

        node(object && d, node * p = nullptr, node * n = nullptr) //移动构造
        :data(d), prev(p), next(n) {}
    };

    int theSize;
    node * head;
    node * tail;

    void Ini(){ //只有初始化(构造)的时候才能调用Ini(),否则一个正常状态下的list对象调用会任意改变对象状态
        theSize = 0;  //所以这个是私有成员
        head = new node{};
        tail = new node{};
        head->next = tail;
        tail->prev = head;
    }
    
    class const_iterator{

        protected: //迭代器必须是只有list可以初始化,不能随便拿个指针就初始化了
            friend class list<object>; //list类需要访问cur
            node * cur;
            const list<object> *theList; //为了防止某个对象操作的时候传的是别的对象的迭代器,必须设置一个类成员用来检测是否指向的是当前对象的
            const_iterator(node * p, const list<object> &lst):cur{p}, theList{lst} {}
        
        public:
            const_iterator():cur(nullptr) {}

            const object & operator *() {
                if(cur == theList->head || cur == nullptr || cur == theList->tail)
                    throw IteratorOutOfBoundsException{}; //自己定义一个抛出异常的函数
                return cur->data;
            }

            const_iterator & operator -- () {
                if(cur == theList->head || cur == nullptr) 
                    throw IteratorOutOfBoundsException{};
                    
                cur = cur->prev;
                return *this;
            }

            const_iterator  & operator ++ () { //前缀++
                if(cur == nullptr || cur == theList->tail) 
                    throw IteratorOutOfBoundsException{};
                cur = cur->next;
                return *this;
            }

            const_iterator operator ++ (int) { //后缀++要先返回,再移动的
                if(cur == nullptr || cur == theList->tail) 
                    throw IteratorOutOfBoundsException{};
                const_iterator old = *this;
                ++(*this);//前缀++已经定义
                return old;
            }

            bool operator == (const const_iterator & rhs)const {
                return cur == rhs.cur;
            }

            bool operator != (const const_iterator & rhs)const {
                return !(*this == rhs); //用公用操作
            }
            
    };

    class iterator : public const_iterator {
        protected:
            friend class list<object>;
            iterator(node * p, const list<object> & lst): const_iterator{p, lst} {}
        
        public:
            iterator() = default;

            object & operator * () {
                if(const_iterator::cur == nullptr || const_iterator::cur == const_iterator::) 
                return const_iterator::cur->data;
            }

            const object & operator * ()const { //????
                return const_iterator::cur->data;
            }

            iterator & operator ++ () {
                this->cur = this->cur->next;
                return *this;
            }

            iterator operator ++ (int) {
                iterator old = *this;
                ++(*this);
                return old;
            }

            iterator & operator -- () {
                this->cur = this->cur->prev;
                return *this;
            }
    };

public:
    list(){
        Ini(); 
    }

    ~list(){
        clear(); delete head; delete tail;
    }

    list(const list & rhs){
        Ini();
        //拷贝rhs中的每一个成员 到 lhs中

        //这里调用push_back的时候,函数里面还会拷贝object的,所以这里就没必要range_for里再拷贝了
        for(auto & x : rhs) push_back(x); //等同于 this->push_back();
    }

    list & operator = (const list & rhs){
        list copy = rhs;
        swap(*this, copy);
        return *this;

        //上面的操作尽量用了公共操作 当然以下做法也可以
        //clear();
        //for(auto & x : rhs) push_back(x);
        //theSize = rhs.theSize;
        //return *this;


        //第一种方法的好处:
        //1.copy离开这个函数作用域之后就会自动析构
        //2.如果rhs的成员特别多,就很麻烦了
    }

    list(list && rhs):theSize{rhs.theSize}, head{rhs.tail}, tail{rhs.tail} {
        rhs.theSize = 0;
        rhs.head = rhs.tail = nullptr; //???为什么这里还可以访问
    }

    list & operator = (list && rhs){ 
        std::swap(theSize, rhs.theSize);
        std::swap(head, rhs.head);
        std::swap(tail, rhs.tail);
        // theSize = rhs.theSize;
        // head = rhs.head; 
        // tail = rhs.tail;
        // rhs.theSize = 0;
        // rhs.head = rhs.tail = nullptr; //???为什么这里还可以访问
        //这里还是在函数内部
        return *this;
    }

    void swap(list & lhs, list & rhs) {
        list copy = std::move(lhs);
        lhs = std::move(rhs);
        rhs = std::move(copy);
    }

    iterator begin(){
        return { head->next };
    }

    iterator  end(){
        return { tail }; //这里返回值不能是左值引用,左值引用不能绑右值
        // iterator t{tail};
        // return t; //不能返回本地变量的引用
    }

    const_iterator begin() const{
        return { head->next };
    }

    const_iterator end() const{
        return { tail };
    }
    
    int size() const {
        return theSize;
    }
    
    int empty() const {
        return theSize == 0;
    }

    void clear(){
        while(!empty()) pop_front();
    }

    //这里都没有任何检查之类的
    object & front(){
        return *begin(); //这里返回iterator也没关系,因为iterator继承了const_..所以可以当成const_用
    }

    const object & front()const {
        return *begin();
    }

    object & back() { //这里--运算符要不要自定义??????
        return *--end(); //返回类型并不是引用类型
    }

    const object & back ()const {
        return *--end();
    }

    void push_front(const object & x) {
        insert(begin(), x);
    }

    void push_front(object && x) {
        insert(begin(), std::move(x));
    }

    void push_back(const object & x) {
        insert(end(), x);
    }

    void push_back(object && x) {
        insert(end(), std::move(x));
    }

    void pop_front() {
        erase(begin());
    }

    void pop_back() {
        erase(--end());
    }


    //这边迭代器为啥不用引用????? 调用该函数的实参必须是左值,这里才能是引用
    iterator & insert(iterator itr, const object & x) {
        if(this != itr.theList) throw IteratorMismatchException{ };
        node * p = itr->cur;
        ++theSize;
        return { p->prev = p->prev->next = new node(x, p->prev, p) };
    }

    iterator insert(iterator  itr, object && x) {
        node * p = itr.cur;
        ++theSize;
        return { p->prev = p->prev->next = new node(std::move(x), p->prev, p) };
    }

    iterator erase(iterator itr) {
        --theSize;
        node * p = itr.cur;
        node * ret{p->next};
        p->prev->next = p->next;
        p->next->prev = p->prev;
        delete p;
        return ret;  //这里返回值也不能是引用
    }

    iterator erase(iterator from, iterator  to) {
        for(iterator itr = from; itr != to;) {
            itr = erase(itr);
        }

        return to;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值