首页IT科技空间配置图(理解空间配置器allocator, 优化STL 中的Vector)

空间配置图(理解空间配置器allocator, 优化STL 中的Vector)

时间2025-06-20 10:47:21分类IT科技浏览4128
导读:.在上一节我们实现的 MyVector存在哪些问题?...

.在上一节我们实现的 MyVector存在哪些问题?

问题1

现在有Student类 class Student{ public: Student(){cout<<"构造Student对象"<<endl;} ~Student(){cout<<"析构Student对象"<<endl;} private: int age char NAME[20;] char *pAddress; } MyVector<Student> v1[1000];

我只是希望创建一个能放1000个Student 的Vector,但是开始并不放任何内容,但是发现编译器除分配了1000个student对象的空间,还创建了1000个对象,

在main函数结束后再析构这1000个对象,这就是问题1,这1000个对象并不是我需要的            ,

原因如下,在MyVector的构造函数中 T * _tep = new T[size](); 这个new除了分配空间,还会调用对象的构造函数完成对象的初始化

换句话说就是 空间的分配和对象的创建联系在了一起,这个非常不合理,我们需要把他分开                  ,我希望是需要帮我开辟空间即可,不希望帮我创建1000个对象

问题2关于析构函数

//析构函数 ~MyVector<T>() { if (Empty() == false) { delete[]first; first = nullptr; last = nullptr; end = nullptr; cout << "析构Vector,堆地址"<<first << endl; } }

实际情况时       ,我的vector是可以放1000个student对象的容器,但是实际里面可能暂时只放了100个对象,

而delete[] first      ,是把整个vector中的1000个student对象都调用析构函数,这也不合理,我们只需要析构有效 数量的对象然后再释放first指针指向的堆内存

问题3 关于添加元素和删除元素

student s1; student s2; student s3; MyVector<student> v1(1000);// 这一句编译器会先分配1000个student对象空间,然后再调用1000次构造函数创建1000个student对象 v1.pushback(s1); //上面这句话会调用赋值函数,会将s1的内容赋值给已经在堆上的student对象,但实际上我想要的是,只需要将分配好的空间 //给我,我使用拷贝构造,将s1拷贝构造出来一个对象放在你给的空间上                  ,这是个问题 v1.popBack(){ this->last--; } //上面的pop最后一个studnet对象,只是将最后一个元素的指针前移动一个student空间大小,并没有去析构这个对象, //而且这个弹出的student对象里面有一个char *pAddress 指向了外部堆内存资源,这个内存自己没有去释放的话, //造成了内存泄漏了. 这个也是个问题,所以说我们要去析构这个弹出的student对象但是不用使用 delete 方式 delete 这个对象,为什么呢? //应为delete 处理调用析构函数完,他还要释放内存空间,但是这个空间属于Vector的,释放掉了这一小块空间,我们后面就无法在使用了             , //**所以一句话就是我们从vector中删除一个对象时      ,只做析构这个对象而不释放他的内存空间,把对象的析构和内存的释放分开**

以上三个问题使得我们不能采用上一篇文字中的方式写Vector                  ,这就是引入了容器的空间配置器的原因

容器的空间配置器做了4件事

内存开辟/内存释放 对象创建/对象析构

在上一遍的基础上加入空间配置器,代码如下

#include <iostream> using namespace std; class student { public: student(int _age, char * _pname): age(_age), pName(_pname){ } student(const student & _rvalue) { this->age = _rvalue.age; this->pName = new char[20]; strcpy(this->pName, _rvalue.pName); } student & operator =(const student & _rvalue) { if (this == &_rvalue) { return *this; } delete[]this->pName; this->pName = nullptr; this->age = _rvalue.age; this->pName = new char[20]; strcpy(this->pName, _rvalue.pName); } ~student() { delete[] this->pName; this->pName == nullptr; cout << "student 析构函数被执行,当前对象地址是" << this << endl; } private: int age; char *pName; }; template<typename T> class MyAllocate { public: T * allocate(int size) { return (T *)malloc(sizeof(T)*size); } //根据指定的地址,释放内存空间 void delAllocate(T *p) { free(p); } //在p指针指定的位置,根据指定的对象创建新对象 void construct(T * p, const T & _rValue) { new (p) T(_rValue); } //析构指定对象,但不释放内存空间 void destory(T * p) { if (p != nullptr) { p->~T(); } } }; template<typename T, typename Allocate=MyAllocate<T>> class MyVector2 { public: //构造函数 MyVector2<T, Allocate>(int size = 10, const Allocate & _allocate = MyAllocate<T>()) : allocator(_allocate) { first = allocator.allocate(size); last = first; end = first + size; cout << "MyVector2 构造函数,构建数量=" << size <<"堆空间构造起始地址="<<first<<"结束地址=" << endl; } //拷贝构造,根据指定的 MyVector2 创建新的MyVector2 MyVector2<T, Allocate>(const MyVector2<T,Allocate> & _rValue) { //1:根据原MyVector2的Size 申请内存空间 first = allocator.allocate(_rValue.Size()); last = first; end = first + __rValue.Size(); //2:根据原MyVector2内的对象,在第1步申请的堆内存中构造对象 T *tep = _rValue.first; while (tep<_rValue.end) { allocate.construct(last, *tep) last++; tep++; } cout << "MyVector2 拷贝构造函数,构建数量" << __rValue.Size() << endl; } //赋值函数 MyVector2<T, Allocate> & operator=(const MyVector2<T, Allocate> & _rValue) { if (this == &_rValue) { return *this;} //1:先析构目标Vector2中所有的对象 T * tep = first; while (tep < last) { allocator.destory(tep); tep++; } //2:释放目标Vector2的内存空间 allocator.delAllocate(first); //3:根据原MyVector2的size 申请新的内存空间 int rSize = _rValue.Size(); T * _head allocator.allocate(rSize); first = _head; last = _head; end = first + rSize; //4:根据原MyVector2中的有效的对象在 第3步申请的内存空间上构建对象 T *tep = _rValue.first; while (tep<_rValue.end) { allocator.construct(last, *tep) last++; tep++; } cout << "MyVector2 赋值函数,构建数量" << rSize << endl; } //在已经申请空间的位置 添加值 void pushBack(const T & _addValue) { if (Full()) { Expend();//两倍扩容 } //在指定地址空间 构建对象 allocator.construct(last, _addValue); cout << "pushBack 元素,内存地址=" << last << endl; last++; } //弹出 void popBack() { if (Empty()) { return; } //1:只析构指定位置对象,但不释放空间 allocator.destory(last - 1); cout << "popBack元素,其内存地址=" << (last - 1) << endl; //2:移动last指针 last--; } //是否为空 bool Empty() { return first == last; } //是否满 bool Full() { return last == end; } int Size() { return end - first; } //容器扩容 void Expend() { int newSize = this->Size() * 2;//两倍扩容 //1:申请新的空间 T * head = allocator.allocate(newSize); T * tep_first = head; T * tep_last = head; T * tep_end = first + newSize; cout << "两倍扩容,新的堆内存起始地址=" << head << endl; //2:将原来有效的对象 赋值到新的堆空间上 T * tep = first; while (tep < last) { allocator.construct(tep_first,*tep); cout << "两倍扩容,赋值对象,原对象地址=" << tep <<"目标对象地址="<<tep_first<< endl; tep_first++; tep_last++; tep++; } tep = first; //3:析构原堆空间上有效的对象 while (tep < last) { allocator.destory(tep); cout << "两倍扩容,析构对象,对象地址=" << tep << endl; tep++; } //4:释放堆上的空间 allocator.delAllocate(first); cout << "两倍扩容,销毁原空间" << first << endl; first = head; last = tep_last; end = first + newSize; } void showVectorInfo() { T * tep = first; while (tep < last) { cout << "打印Vector中有效对象地址=" << tep << endl; tep++; } } private: T * first; T * last; T * end; Allocate allocator; }; int main() { MyVector2<student, MyAllocate<student>> v(4); student s1(20, "zs1"); v.pushBack(s1); student s2(22, "zs2"); v.pushBack(s2); student s3(23, "zs3"); v.pushBack(s3); student s4(24, "zs4"); v.pushBack(s4); v.showVectorInfo(); student s5(25, "zs5"); v.pushBack(s5); v.showVectorInfo(); system("pause"); return 1; }

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
ubuntu好用的pdf阅读器(ubuntu下chm和PDF阅读器 « 小居)