zoukankan      html  css  js  c++  java
  • 定义自己的STL容器 (1)

    如何借助STL开发自己的容器?

    STL(Standard Template Library, 标准模板库)使用容器(Container)、迭代器(Iterator)、算法(Algorithm)构建了一个强大的框架,它允许我们使用STL中的容器存储任何类型的数据,并通过迭代器来存取,或者是调用STL中的算法。那么如何设计自己的模板,使之可以借助STL的算法以达到某些便捷的效果?

    设计分配器

    借助allocator<T>来设计容器存储的数据类型,其中value_type即为容器中所存储的数据的类型。分配器(Allocator)负责为模板分配空间,释放空间。在此,我们不使用封装技术设计自定义的Allocator类,而是直接为模板分配空间,STL模板库在底层使用类似的方法为模板分配空间。

    
    
    typedef typename allocator<T>::value_type value_type;
    typedef typename allocator<T>::size_type size_type;

    void
    init_space(size_type size){ begin_ = (iter)::operator new(size*sizeof(value_type)); end_ = begin_+size; }

    迭代器

    typedef value_type* iter;

    迭代器实际上是value_type类型指针。

    数据成员

    由于设计简易vector不涉及容量方面的操作,故一个首部迭代器和一个尾部迭代器便足够。

    iter begin_;
    iter end_;

    成员函数

    主要实现以下几个函数:构造函数、插入、删除、判空、获取元素个数、[]重载。

    需要注意的是 insert() 与 erase() 函数:

    void insert(iter ins_iter, size_type&& value){//以右值插入为例
        uninitialized_copy(ins_iter, end_, ins_iter+1);//用以将 [插入位置,结束位置) 的值复制到 [插入位置+1,新的结束位置)
        *ins_iter = move(value); //将 插入位置 的值更新为待插入值 value
        ++end_; //由于只插入了一个值,将尾部迭代器++即可,插入多个值的情况可依此设计
    }
    void erase(iter ers_iter){
            assert(ers_iter < end_ && ers_iter >= begin_);
            uninitialized_copy(ers_iter+1, end_, ers_iter);//将 [删除位置+1,结束位置) 的值复制给 [删除位置,结束位置-1)
            (end_-1)->~T();//注意:此处一定要使用泛型的析构函数
            --end_;//由于只删除了一个元素,末尾迭代器--即可,删除多个元素可依照此设计
    }

    完整实现

    头文件:demo.h

    #ifndef Demo_H
    #define Demo_H
    
    #include <memory>
    #include <iterator>
    #include <cassert>
    
    using namespace std;
    
    template<typename T>
    class Demo{
    public:
        typedef typename allocator<T>::value_type value_type;
        typedef typename allocator<T>::size_type size_type;
    
        typedef value_type* iter;
    
    public:
        
        //构造函数
        Demo() {
        }
    
        //以空间n构造
        Demo(size_type n){
            init_space(n);
            uninitialized_fill(n, value_type());
        }
    
        //以n个实值构造
        Demo(size_type n, const value_type& value){
            init_space(n);
            uninitialized_fill_n(begin_, n, value);
        }
    
        //拷贝构造函数
        Demo(const Demo& demo){
            init_space(static_cast<size_type>(demo.end_ - demo.begin_));
            uninitialized_copy(demo.begin_, demo.end_, begin_);
        }
    
        //操作符重载
        const value_type& operator[](size_type idx) const{
            assert(idx < size());
            return *(begin_+idx);
        }
    
        value_type& operator[](size_type idx){
            assert(idx < size());
            return *(begin_+idx);
        }
    
        
        //增删改查
        void insert(iter ins_iter, const size_type& value){
            insert(ins_iter, value);
        }
    
        void insert(iter ins_iter, size_type&& value){
            uninitialized_copy(ins_iter, end_, ins_iter+1);
            *ins_iter = move(value);
            ++end_;
        }
        
        void erase(iter ers_iter){
            assert(ers_iter < end_ && ers_iter >= begin_);
            uninitialized_copy(ers_iter+1, end_, ers_iter);
            (end_-1)->~T();
            --end_;
        }
        
    
        //基础部分
        bool empty(){
            return begin_ == end_;
        }
        
        size_type size(){
            return static_cast<size_type>(end_ - begin_);
        }
        
        iter begin(){
            return begin_;
        }
        
        iter end(){
            return end_;
        }
    
    
    private:
    
        iter begin_;
        iter end_;
        
        //不对外用于内部调用公开的方法
        void init_space(size_type size){
            begin_ = (iter)::operator new(size*sizeof(value_type));
            end_ = begin_+size;
        }
    };
    
    #endif //Demo_H

    测试

    源文件:main.cpp

    #include <iostream>
    #include "demo.h"
    #include <algorithm>
    
    int main() {
        using namespace std;
    
        Demo<int> demo(10, 1024);
    
        cout<<"---------size()----------
    ";
        cout<<demo.size()<<endl;
    
        cout<<"---------end()----------
    ";
        cout<<*(demo.end()-1)<<endl;
    
        cout<<"---------迭代器----------
    ";
        for(auto it = demo.begin();it != demo.end();++it){
            cout<<*it << " ";
        }
        cout<<"
    ";
    
        cout<<"--------下标运算符--------
    ";
        for (int i = 0; i < 10; ++i) {
            cout<<demo[i]<<" ";
        }
        cout<<"
    ";
    
        demo.insert(demo.begin(), 1000);
        cout<<"---------插入----------
    ";
        for(auto it = demo.begin();it != demo.end();++it){
            cout<<*it << " ";
        }
        cout<<"
    ";
    
        demo.erase(demo.begin());
        cout<<"---------删除----------
    ";
        for(auto it = demo.begin();it != demo.end();++it){
            cout<<*it << " ";
        }
        cout<<"
    ";
    
        *(demo.begin()) = 2;*(demo.begin()+1) = 4;*(demo.begin()+2) = 8;*(demo.begin()+3) = 16;*(demo.begin()+4) = 32;*(demo.begin()+5) = 64;
        demo[6] = 128;demo[7] = 256;demo[8] = 512;demo[9] = 1024;
        cout<<"---------赋值----------
    ";
        for(auto it = demo.begin();it != demo.end();++it){
            cout<<*it << " ";
        }
        cout<<"
    ";
    
        sort(demo.begin(), demo.end(), greater<int>());
        cout<<"---------调用sort函数----------
    ";
        for(auto it = demo.begin();it != demo.end();++it){
            cout<<*it << " ";
        }
        cout<<"
    ";
    
        cout<<"---------调用max_element函数----------
    ";
        cout<<"max value="<<*max_element(demo.begin(), demo.end())<<endl;
        cout<<"
    ";
    
        return 0;
    }

    结果

    ---------size()----------
    10
    ---------end()----------
    1024
    ---------迭代器----------
    1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 
    --------下标运算符--------
    1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 
    ---------插入----------
    1000 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 
    ---------删除----------
    1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 
    ---------赋值----------
    2 4 8 16 32 64 128 256 512 1024 
    ---------调用sort函数----------
    1024 512 256 128 64 32 16 8 4 2 
    ---------调用max_element函数----------
    max value=1024

    成功通过自定义的模板调用STL中的函数。

    更进一步

    这个过程中,alloctor与迭代器的设计与使用是重中之重,如何更进一步使用memory头文件中的allocator,与iterator头文件中不同种类的迭代器,是设计出更复杂更实用的容器的基石。

  • 相关阅读:
    pc 端支付宝支付流程
    crontab
    Java集合之HashSet
    Java内存与垃圾收集知识总结
    Volley设计思想和流程分析
    java内部类
    HandlerThread源码分析
    IntentService源码分析
    Android消息机制:Looper,MessageQueue,Message与handler
    LeetCode340 Longest Substring with At Most K Distinct Characters
  • 原文地址:https://www.cnblogs.com/icky1024/p/STL-selfSTL.html
Copyright © 2011-2022 走看看