zoukankan      html  css  js  c++  java
  • c++ vector 简单实现。

    第二次修改:

    1)熟悉基本的模板编程,头文件和定义必须放到一起。

    2)熟悉内存管理模板类 allocator<T>。

    1.使用标准库的内存管理类 allocator<T>  代替原来c的malloc和free。 可以给无默认构造函数的类分配指定空间。
    2.第一次写的时候,只free vectore元素占用内存, 没有调用元素的析构函数,那个时候还没有搞清楚,析构什么时候会调用。free 是无法调用析构函数的。
    3.模板类的编译问题:
    因为是模板类,有类型参数,类的方法编译的时候,不能确定所占用的栈大小.必须使用的时候才能确定,而且不同的T类型,有不同的方法地址.所以申明定义放到一起
    4.myalloc.destroy(pb);//仅仅调用析构函数.

      5)void *memset(void *s, int ch, size_t n);
      函数解释:将s中当前位置后面的n个字节 (typedef unsigned int size_t )用 ch 替换并返回 s 。
    #ifndef MYVECTOR_H_INCLUDED
    #define MYVECTOR_H_INCLUDED
    //allocator<T> a;                           定义一个T类型的allocator对象。
    //a.allocate(n);                            申请n个T大小的,未分配的空间。类似(T*) malloc(sizeof(T)*n)
    //a.deallocate(p,n)                         释放内存,p为T*,n为释放的T类型对象的数量。注意:T类型对象本身,如有需要释放的资源,必须先释放,a.deallocate(p,n)只是释放对象本身的内存,而对象的建立又额外申请的资源,需要另外处理。
    //a.construct(p,t)                          复制构造,用t来复制构造。相当于 new (p) T(t),这个是placement new的用法  new(place_address) type(initializer-list)
    //a.destroy(p)                 调用pd对象的析构函数。
    //uninitialized_copy(startit,endit,it) startit,endit :要复制的开始迭代器地址和结束地址。it:要复制的迭代器地址。 //uninitialized_fill(startit,endit,obj) startit,endit :要复制的开始迭代器地址和结束地址。it:要复制的对象。 使用复制构造函数填充内存 //uninitialized_fill_n(startit,endit,obj,n) startit,endit :要复制的开始迭代器地址和结束地址。it:要复制的对象。 n,要复制的数量。 使用复制构造函数填充内存 //因为是模板,有类型参数,类的方法编译的时候,不能确定所占用的栈大小.必须使用的时候才能确定,而且不同的T类型,有不同的方法地址.所以申明定义放到一起 #include <memory> #include <stdexcept> #include <iostream> using namespace std; template<typename T> class myVector{ public: //如果分配错误呢? myVector():pbegin(myalloc.allocate(defautlSize)),pend(pbegin),pcapcity(pbegin+defautlSize),Vsize(0),Vcapcity(defautlSize){} void push_back(const T& _obj) { if(pend>=pcapcity) { T* pTempAlloc=myalloc.allocate(Vcapcity*2); T* pPrep=pbegin; if(pTempAlloc!=0) { uninitialized_copy(pbegin,pend,pTempAlloc); pbegin=pTempAlloc; pend=pbegin+Vsize; pcapcity=pbegin+(Vcapcity*2); Vsize=Vsize; Vcapcity+=Vcapcity; //清理原资源. destroyS(pPrep,pPrep+Vsize,pPrep+Vsize); } else { throw runtime_error("error allocator!"); } } myalloc.construct(pend,_obj); ++pend; ++Vsize; } void erase(unsigned int index) { if(index>=0&& index<Vsize) { myalloc.destroy(pbegin+index);//手动调用对象析构 for(int i=index+1;i!=Vsize;++i)//往前覆盖.最后一个对象占用的内存,不管了.pend往前移动就好. { uninitialized_copy(pbegin+i,pbegin+i+1,pbegin+i-1); } --Vsize; --pend; } else { throw runtime_error("index over range."); } } ~myVector() { destroyS(pbegin,pend,pcapcity); } myVector(const myVector& _obj) { pbegin=myalloc.allocate(_obj.Vcapcity); pend=pbegin+_obj.Vsize; pcapcity=pbegin+_obj.Vcapcity; Vsize=_obj.Vsize; Vcapcity=_obj.Vcapcity; uninitialized_copy(_obj.pbegin,_obj.pend,pbegin); } myVector& operator=(const myVector& _obj) { if(&_obj!=this) { destroyS(pbegin,pend,pcapcity); pbegin=myalloc.allocate(_obj.Vcapcity); pend=pbegin+_obj.Vsize; pcapcity=pbegin+_obj.Vcapcity; Vsize=_obj.Vsize; Vcapcity=_obj.Vcapcity; uninitialized_copy(_obj.pbegin,_obj.pend,pbegin); } return *this; } int size() { return pend-pbegin; } int capcity() { return pcapcity-pbegin; } void showInfo() { cout<<"pbegin:"<<(void *)pbegin<<". size:"<<Vsize<<". capcity"<<Vcapcity<<". pend:"<<(void *)pend<<endl; T* pb=pbegin; for(pb;pb!=pend;++pb) { cout<<*pb<<endl; } } private: static allocator<T> myalloc; const static int defautlSize=3; T* pbegin; T* pend; T* pcapcity; unsigned int Vcapcity; unsigned int Vsize; void destroyS(T* PS,T* PE,T* PC) { T* pb=PS; for(pb;pb!=PE;++pb) { myalloc.destroy(pb);//仅仅调用析构函数. } myalloc.deallocate(PS,PC-PS); } }; //int book::pid=6 template<typename T> allocator<T> myVector<T>::myalloc=allocator<T>(); #endif // MYVECTOR_H_INCLUDED

    实现功能基本:

    插入元素,pushback.
    引用构造,
    copy功能.
    按索引返回.
    删除索引位置元素.

    备注:
    //默认大小为32个数据元素。新插入不够,空间翻倍,为32,64,128。。。。
    //引用构造,新对象和引用对象一致。 copy复制,先检测空间,若空间不够,调整为右直的大小。
    //注意capcity 的const。是为了MyVector2(const MyVector2<T>&);

    有几个新知识点:

    1)placement new 的写法 。给 一个已经申请内存的空间。放入对象值。new是先申请后放入。这里省去申请。

    new(endP) T(*s_iterator);//placement new .

    2)int类型的数据与unsigned int类型的数据进行比较时会把int类型的数据转换为unsigned int 类型的数据,然后再进行比较。

    所以 int -1会大于 unsigned 0.

    3)pushback 中。空间 不够 。要申请空间。注意不要建立临时对象,再吧临时对象的数据给左值。 因为临时对象离开pushback韩素 会析构。导致左值的结果被删除了。

    测试发现有问题的同学,这里看看自己有没有犯同样的错误。

    所以直接申请空间。再把地址给左值就好了。

    myvector2.h

    #ifndef MYVECTOR2_H_INCLUDED
    #define MYVECTOR2_H_INCLUDED
    
    #include "malloc.h"
    #include <iostream>
    using namespace std;
    //实现功能基本:插入元素,pushback.
    //引用构造,
    //copy功能.
    //按索引返回.
    //删除索引位置元素.
    
    
    //默认大小为32个数据元素。新插入不够,空间翻倍,为32,64,128。。。。
    //引用构造,新对象和引用对象一致。 copy复制,先检测空间,若空间不够,调整为右直的大小。
    //注意capcity 的const。是为了MyVector2(const MyVector2<T>&);
    
    template<typename T>
    class MyVector2{
    public:
        MyVector2();
        MyVector2(const MyVector2<T>&);
        MyVector2<T> & operator=(const MyVector2<T>&);//copy操作,左直是一定存在的。所以可以返回引用。
        int PushBack(const T&);
        T& operator[](unsigned int);
        unsigned int size()const;
        unsigned int capcity()const;//注意capcity 的const。是为了MyVector2(const MyVector2<T>&);中,参数是const.而且还调用了参数的capcity()方法.所以方法必须const.
    
        void erace(unsigned int);
    
        ~MyVector2()
        {
            del();
        }
    
    private:
        T* firstP;
        T* endP;
        T* CapicityP;
        static const unsigned int stepsize=32;
    
    
        void addEnd();
        void del();
    
        MyVector2(unsigned int);//private 指定模板数据类型数量来初始化类.
    };
    
    template<typename T>
    MyVector2<T>::MyVector2():firstP((T*)malloc(sizeof(T)*stepsize)),endP(firstP)
    {
        CapicityP=firstP+stepsize;//不知为什么,如果防入初始化.CapicityP是莫名的数据.
        cout<<"c malloc:"<<firstP<<endl;
    }
    
    
    template<typename T>
    MyVector2<T>::MyVector2(const MyVector2<T>& _rhs):firstP((T*)malloc(sizeof(T)*_rhs.capcity())),endP(firstP)
    {
        cout<<"ref malloc:"<<firstP<<endl;
        CapicityP=firstP+_rhs.capcity();
        T* s_iterator=_rhs.firstP;
        for(s_iterator;s_iterator!=_rhs.endP;++s_iterator)
        {
            new(endP) T(*s_iterator);//placement new .
            ++endP;
        }
    }
    
    
    template<typename T>
    MyVector2<T> & MyVector2<T>::operator=(const MyVector2<T>& _rhs)
    {
        if(this->capcity()>=_rhs.size())
        {
            this->endP=this->firstP;
    
            T* s_iterator=_rhs.firstP;
            for(s_iterator;s_iterator!=_rhs.endP;++s_iterator)
            {
                new(endP) T(*s_iterator);//placement new .
                ++endP;
            }
        }
        else
        {
            del();
    
            T* TempfirstP=(T*)malloc(sizeof(T)*_rhs.capcity());
            T* TempendP=TempfirstP;
            T* TempCapcityP=TempfirstP+(_rhs.capcity());
    
            cout<<"copy malloc:"<<TempfirstP<<endl;
    
            T* s_iterator=_rhs.firstP;
            for(s_iterator;s_iterator!=_rhs.endP;++s_iterator)
            {
                new(TempendP) T(*s_iterator);//placement new .
                ++TempendP;
            }
    
            firstP=TempfirstP;
            endP=TempendP;
            CapicityP=TempCapcityP;
    
        }
        return *this;
    }
    
    template<typename T>
    MyVector2<T>::MyVector2(unsigned int _tsize):firstP((T*)malloc(sizeof(T)*_tsize))
    {
        endP=firstP;
        CapicityP=firstP+_tsize;
    }
    
    template<typename T>
    void MyVector2<T>::erace(unsigned int _index)
    {
        //endp 减1。index以下数据望上移动。
        //:int类型的数据与unsigned int类型的数据进行比较时会把int类型的数据转换为unsigned int 类型的数据,然后再进行比较。
        //坑太多。。。。这里size 为0的花。size-1为-1。按照规则会比无符号的0大。。。
        if(_index>=0 && _index<=this->size()-1 && this->size()>0)//
        {
    
            T* titerator=this->firstP+_index+1;
    
            for(titerator;titerator!=this->endP;++titerator)
            {
                new(this->firstP+_index) T(*(this->firstP+_index+1));
            }
            --endP;
        }
    }
    
    
    template<typename T>
    unsigned int MyVector2<T>::size()const
    {
        return endP-firstP;
    }
    
    
    template<typename T>
    unsigned int MyVector2<T>::capcity()const
    {
        return CapicityP-firstP;
    }
    
    
    
    template<typename T>
    void MyVector2<T>::addEnd()
    {
        ++endP;
    }
    
    template<typename T>
    int MyVector2<T>::PushBack(const T& _T)
    {
        int result=-1;
        if(endP>=firstP && endP<CapicityP)
        {
            new (endP) T(_T);
            ++endP;
        }
        else
        {
            //MyVector2<T> temp=MyVector2(2*size());//最开始一直出错.debug才发现,犯了一个基础知识错误.
            //这里建立的对象,离开作用域会调用西够函数.所以直接分配内存,而不是建立临时对象.免去西构问题.
            T* TempfirstP=(T*)malloc(sizeof(T)*2*size());
            T* TempendP=TempfirstP;
            T* TempCapcityP=TempfirstP+(2*size());
    
            cout<<"pushback malloc:"<<TempfirstP<<endl;
    
            T* s_iterator=this->firstP;
            for(s_iterator;s_iterator!=(this->endP);++s_iterator)
            {
                new(TempendP) T(*s_iterator);//placement new .
                ++TempendP;
            }
    
            del();
    
            new (TempendP) T(_T);
            ++TempendP;
    
            firstP=TempfirstP;
            endP=TempendP;
            CapicityP=TempCapcityP;
        }
        return result;
    }
    
    template<typename T>
    T& MyVector2<T>::operator[](unsigned int _index)
    {
        if(_index>0)
        {
            return *(firstP+_index);
        }
        else
        {
            return *firstP;
        }
    }
    
    template<typename T>
    void MyVector2<T>::del()
    {
        cout<<"del:"<<firstP<<endl;
        free (firstP);
    }
    
    #endif // MYVECTOR2_H_INCLUDED
    

      

    main.cpp

    #include <iostream>
    #include <vector>
    #include "myvector2.h"
    
    using namespace std;
    
    //为什么mb[0]=b2;是ok的.但是设计myvector中firstP=_T;确不行?
    //为什么CapicityP=firstP+stepsize;防在函数体内每问题.而防入初始化却有问题?
    
    struct book
    {
    public:
        book():name(""),bn(0),price(0){}
        book(const string& _name,const int _bn,const double _price):name(_name),bn(_bn),price(_price){}
    
        book& operator=(const book& _lhs)
        {
            name=_lhs.name;
            bn=_lhs.bn;
            price=_lhs.price;
            return *this;
        }
        book(const book& _rhs)
        {
            name=_rhs.name;
            bn=_rhs.bn;
            price=_rhs.price;
        }
        string bName()
        {
            return name;
        }
        void changeName(const string& _name)
        {
            name=_name;
        }
        ~book(){}
    private:
        string name;
        int bn;
        double price;
    };
    
    void mainMyVector2();
    void showInfo(const MyVector2<book>& books);
    int main()
    {
        mainMyVector2();
        //mainString();
        //mainMyVector();
    
        return 0;
    }
    
    void mainMyVector2()
    {
        //实现功能基本:插入元素,pushback.
        //引用构造,
        //copy功能.
        //按索引返回.
        //删除索引位置元素.
    
        book b1=book("c++",01,2.5);
        book b2=book("c",02,2);
        book b3=book("c#",03,3.1);
    
        cout<<"*************push back***********"<<endl;
        MyVector2<book> books1;//不需要book类有默认构造函数,因为使用的是c的malloc分配空间函数。而不是new建立数组。
        books1.PushBack(b1);
        books1.PushBack(b2);
        books1.PushBack(b3);
        showInfo(books1);
    
        for(int i=0;i!=40;++i)
        {
            books1.PushBack(b2);
        }
        showInfo(books1);
    
        cout<<"*************ref construct***********"<<endl;
        MyVector2<book> books2=books1;//注意这里是构造初始化而不是copy。
        showInfo(books2);
    
        cout<<"**************copy***********"<<endl;
        MyVector2<book> books_capcity32;
        showInfo(books_capcity32);
    
        books_capcity32=books1;
        showInfo(books_capcity32);
    
        cout<<"*************index***********"<<endl;
        cout<<"index 38:"<<books_capcity32[38].bName()<<".  first:"<<books_capcity32[0].bName()<<endl;
    
        cout<<"*************earse***********"<<endl;
        MyVector2<book> books3;
        for(int i=0;i!=books3.size();++i)
        {
            cout<<books3[i].bName()<<endl;
        }
        showInfo(books3);
    
        books3.erace(0);
    
        books3.PushBack(b1);
        books3.erace(0);
        for(int i=0;i!=books3.size();++i)
        {
            cout<<books3[i].bName()<<endl;
        }
        showInfo(books3);
    
        books3.PushBack(b1);
        books3.PushBack(b2);
        books3.PushBack(b3);
    
        for(int i=0;i!=books3.size();++i)
        {
            cout<<books3[i].bName()<<endl;
        }
        books3.erace(1);
    
        for(int i=0;i!=books3.size();++i)
        {
            cout<<books3[i].bName()<<endl;
        }
    
        showInfo(books3);
    }
    
    void showInfo(const MyVector2<book>& books)
    {
        cout<<"size:"<<books.size()<<". capcity:"<<books.capcity()<<endl;
    }
    
    

      

  • 相关阅读:
    关于enum ,调用webservice,用户控件与主页面之间的交互,datsource属性,net面试题,反射类生成sql语句,URl重写一个小实例
    一个很简单的图片上传后立即显示在页面的控件(c#)
    委托之实现异步调用
    跟我学Linq
    w3c关于sql sever的基础操作
    join操作基础
    表操作基础
    javascript理论篇(详情见地址)
    android universal-image-loader的使用
    json相关类库,java对象与json相互转换
  • 原文地址:https://www.cnblogs.com/lsfv/p/5807283.html
Copyright © 2011-2022 走看看