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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
#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

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#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;
}

  

posted @   琴鸟  阅读(2069)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示