C++ STL标准库解析|vector向量对象的迭代器实现vector::iterator

在前面的文章中,我们实现了以下几步:

【简单实现STL容器vector代码】
【⭐️vector容器的空间配置器allocator】

并且我们已经实现了string对象的迭代器,那么今天必然是填vector得坑啦!
【实现string类的迭代器string::iterator】

回顾完前面的文章,现在开整!

提供operator[]

首先我们需要把vector当作数组下标一样来使用。

T& operator[](int index) { // vec[2]
    if (index < 0 || index >= size()) {
        throw "OutOfRangeException";
    }
    return _first[index]; 
}

实现迭代器嵌套类和begin(),end()方法

首先要明确的迭代器一般实现成容器的嵌套类型。这样用户使用起来无感,把底层数据结构的差异性都封装在迭代器中。

再一个,需要提供begin()和end()返回一个迭代器类型,并且分别返回的是特定位置的迭代器。

class iterator {
    public:
        iterator(T *ptr = nullptr) : _ptr(ptr) {}
    private:
        T *_ptr;
    };
//需要给容器提供begin和end方法
iterator begin() { return iterator(_first); }
iterator end() { return iterator(_last); }

提供operator!=\operator++()

我们只读不写的方法最好写成常方法,这样常量对象和非常量对象都可以调用。有疑问请跳转该文章【把类成员方法声明为常方法的必要性】

bool operator!=(const iterator &it) const {
    return _ptr != it._ptr;
}

我们的vector容器底层是一个数组,所以不等于是底层对应的指针不等于。

接下来我们需要重载前置++运算符,如果有不懂的,请移步:【++i和i++的效率问题|重载前置++运算符和重载后置++运算符】

void operator++ () {
	_ptr++;
}

容器底层是一个数组,所以迭代器的++就是底层指针的++

重载operator*

迭代器解引用就是容器底层的指针解引用

T& operator*() { return *_ptr; }

在这里我们为什么不用常方法呢,因为我们希望能够利用解引用来个变量赋值:
int data = *it;

当然了,最好的解决办法就是我们再给他提供一个常方法:

const T& operator*() const { return *_ptr; }

测试代码

int main () {
    vector<int> vec;
    for (int i = 0; i < 20; i++) {
        vec.push_back(rand() % 100 + 1);
    }

    int size = vec.size();
    for (int i = 0; i < size; i++) {
        std::cout << vec[i] << " ";
    }
    std::cout << std::endl;

    vector<int>::iterator it = vec.begin();
    for (; it != vec.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;

	for (int val : vec) { //foreach底层原理就是通过容器的迭代器来实现的容器遍历
		cout << val << " "
	}
	cout << endl;

    return 0;
}

没啥毛病!

vector最终代码

template<typename T>
struct Allocator {
    T* allocate(size_t size) {//只负责内存开辟
        return (T*)malloc(size * sizeof(T));
    }
    void deallocate(void *p) { // 负责内存释放
        free(p);
    } 
    void construct(T *p, const T &val) {//复杂对象构造
        new (p) T(val);
    }
    void destroy(T *p) { //负责对象析构
        p->~T();    // ~T()代表了T类型的析构函数
    }
};

template <typename T, typename Alloc = Allocator<T> >
class vector {
public:
    vector(int size = 10) {
        //_first = new T[size];
        _first = _allocator.allocate(size);
        _last = _first;
        _end = _first + size;
    }
    ~vector() {
        //delete[] _first;
        for(T *p = _first; p != _last; ++p) {
            _allocator.destroy(p);  //把_first指针指向的数组的有效元素进行析构操作
        }
        _allocator.deallocate(_first); //释放堆上的内存
        _first = _last = _end =nullptr;
    }
    vector(const vector<T> &rhs) {
        int size = rhs._end - rhs._first;
        //_first = new T[size];
        _first = _allocator.allocate(size);
        int len = rhs._last - rhs._first;
        for (int i = 0; i < len; ++i) {
            //_first[i] = rhs._first[i];
            _allocator.construct(_first + i, rhs._first[i]);
        }
        _last = _first + len;
        _end = _first + size;
    }
    vector<T>& operator=(const vector<T> &rhs) {
        if (this == rhs) return *this;
        
        //delete[]_first;
        for(T *p = _first; p != _last; ++p) {
            _allocator.destroy(p);  //把_first指针指向的数组的有效元素进行析构操作
        }
        _allocator.deallocate(_first); //释放堆上的内存

        int size = rhs._end - rhs._first;
        //_first = new T[size];
        _first = _allocator.allocate(size);
        int len = rhs._last - rhs._first;
        for (int i = 0; i < len; ++i) {
            //_first[i] = rhs._first[i];
            _allocator.construct(_first + i, rhs._first[i]);
        }
        _last = _first + len;
        _end = _first + size;

        return *this;
    }

    void push_back(const T &val) {
        if (full()) expand();
        //*_last++ = val; _last指针指向的内存构造一个值为val的对象
        _allocator.construct(_last, val);
        _last++;
    }

    void pop_back() {
        if (empty()) return ;
        //--_last; 不仅要把_last--,还需要析构删除的元素
        --_last;
        _allocator.destroy(_last);
    }

    T back() const {    //返回容器末尾元素的值
        return *(_last - 1);
    }

    bool full() const { return _last == _end; }
    bool empty() const { return _first == _last; }
    int size() const { return _last - _first; }

    T& operator[](int index) { // vec[2]
        if (index < 0 || index >= size()) {
            throw "OutOfRangeException";
        }
        return _first[index]; 
    }

    //迭代器
    class iterator {
    public:
        iterator(T *ptr = nullptr) : _ptr(ptr) {}
        bool operator!=(const iterator &it) const {
            return _ptr != it._ptr;
        }
        void operator++() {
            _ptr++;
        }
        T& operator*() { return *_ptr; }
        const T& operator*() const { return *_ptr; }
    private:
        T *_ptr;
    };
    //需要给容器提供begin和end方法
    iterator begin() { return iterator(_first); }
    iterator end() { return iterator(_last); }
    
private:  
    T *_first;  //指向数组起始的位置
    T *_last;  //指向数组中有效元素的后继位置
    T *_end;  //指向数组空间的后继位置
    Alloc _allocator; //定义容器的空间配置器对象

    void expand() { //容器的二倍扩容操作
        int size = _end - _first;
        //T *ptemp = new T[2 * size];
        T *ptemp = _allocator.allocate(2 * size);

        for (int i = 0; i < size; ++i) {
            //ptemp[i] = _first[i];
            _allocator.construct(ptemp + i, _first[i]);
        }
        //delete[] _first;
        for (T *p = _first; p != _last; ++p) {
            _allocator.destroy(p);
        }
        _allocator.deallocate(_first);
        _first = ptemp;
        _last = _first + size;
        _end = _first + 2 * size;
    }
};
  • 8
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值