reallocate(C++类内使用allocator的问题)
本文目录
C++类内使用allocator的问题
allocator《T》 a a可以为类型为T的对象分配内存
a.allocate(n) 分配一段原始的未构造的内存,可以保存n个T类型的对象
a.deallocate(p,n) 释放T*指针p中地址开始的内存,保存了n个类型为T的对象;p必须是allocate返回的指针,n必须是p创建时所要求的大小,必须保证这些指针调用过destroy
a.construct(p, args) p必须是T*指针,指向原始内存,args传递给构造函数
a.destroy(p) p位T*指针,对p执行析构函数(销毁)
使用须知:
不要使用未构造的内存,小心越界,释放之前一定要销毁,只能销毁真正构造了得元素
p(内存未构造)----》p(可以使用)---------》p(使用结束)------------》p(释放内存)
a.allocate(p) a.construct(p) a.destroy(p) a.deallocate(p)
指针不能为空
例子:
动态内存管理类StrVec模仿std::vector《std::string》
使用allocator分配内存
指针成员
-----------未构造元素------------
^ ^ ^
|elements |first_free |cap
elements 分配的内存的首元素
first_free 实际元素之后的位置(已构造元素的尾后元素,未构造元素的首元素)
cap 分配内存末尾之后的位置
allocator《string》内存分配器
方法:
alloc_n_copy 分配内存,拷贝元素
free 销毁元素,释放内存
chk_n_alloc 检查空间,不够则分配新内存
reallocate 分配心内存
定义:
class StrVec{public: StrVec(): //默认初始化 elements(nullptr), first_free(nullptr), cap(nullptr){} StrVec(const StrVec &s)//拷贝构造函数 { //分配内存,大小与s一样 auto newdata = alloc_n_copy(s.begin(), s.end()); elements = newdata.first; first_free = cap = newdata.second; } StrVec &operator=(const StrVec &rhs)//拷贝赋值 { //分配内存,大小与rhs一样 auto data = alloc_n_copy(rhs.begin(), rhs.end()); free(); elements = data.first; first_free = cap = data.second; return *this; } ~StrVec()//析构 {free();} void push_back(const std::string&)//拷贝元素(别告诉我你没见过这个名字) { chk_n_alloc(); //检查空间 alloc.construct(first_free++, s); //构造s的副本(注意后置递增) } size_t size() const {return first_free - elements;} size_t capacity() const {return cap - elements;} //这些都是vector的名字,一个效果 std::string *begin() const{return elements;} std::string *end() const{return first_free;}//前面解释过了private: Static std::allocator《std::string》 alloc;//分配元素 void chk_n_alloc() { if(size() == capacity()) //分配的内存用完 reallocate(); //重新分配 } std::pair《std::string*, std::string*》 alloc_n_copy(const std::string*, const std::string*) { //分配空间 auto data = alloc.allocate(e - b); return {data, uninitialized_copy(b, e, data)}; } void free() //销毁元素释放内存 { //不能传递给deallocate一个空指针,如果为零,函数不作为 if(elements) { //逆序销毁旧元素(析构) for (auto p = first_free; p != elements;/*空下*/) alloc.destory(--p);//这里先递减,递减后的指针销毁 //这里释放内存空间 alloc.deallocate(elements, cap - elements); } } void reallocate()//重新分配内存 { //分配两倍的空间 auto newcapacity = size() ? 2 * size() : 1; //1的作用是因为0 * 2 = 0,使空元素分配一个空间 auto newdata = alloc.allocate(newcapacity); //将数据从旧内存移动到新内存 auto dest = newdata; auto elem = elements; for(size_t i = 0;i != size(); ++i) alloc.construct(dest++, std::move(*elem++)); free(); //更新数据结构 elements = newdata; first_free = dest; cap = elements + newcapacity; } std::string *elements; std::string *first_free; std::string *cap;//前面讲过};关于realloc的用法
我也挺厚道的,给你一段能看懂的:realloc 原型:extern void *realloc(void *mem_address, unsigned int newsize); 功能:改变mem_address所指内存区域的大小为newsize长度。 说明:如果重新分配成功则返回指向被分配内存的指针,否则返回空指针NULL。 当内存不再使用时,应使用free()函数将内存块释放。 注意:这里原始内存中的数据还是保持不变的。 举例: // realloc.c #include 《syslib.h》 #include 《alloc.h》 main() { char *p; clrscr(); // clear screen p=(char *)malloc(100); if(p) printf(“Memory Allocated at: %x“,p); else printf(“Not Enough Memory!\n“); getchar(); p=(char *)realloc(p,256); if(p) printf(“Memory Reallocated at: %x“,p); else printf(“Not Enough Memory!\n“); free(p); getchar(); return 0; } 详细说明及注意要点: 1、如果有足够空间用于扩大mem_address指向的内存块,则分配额外内存,并返回mem_address 这里说的是“扩大”,我们知道,realloc是从堆上分配内存的,当扩大一块内存空间时, realloc()试图直接从堆上现存的数据后面的那些字节中获得附加的字节,如果能够满足,自然天下太平。也就是说,如果原先的内存大小后面还有足够的空闲空间用来分配,加上原来的空间大小= newsize。那么就ok。得到的是一块连续的内存。 2、如果原先的内存大小后面没有足够的空闲空间用来分配,那么从堆中另外找一块newsize大小的内存。 并把原来大小内存空间中的内容复制到newsize中。返回新的mem_address指针。(数据被移动了)。 老块被放回堆上。 例如: #include 《malloc.h》 char *p,*q; p = (char * ) malloc (10); q=p; p = (char * ) realloc (p,20); ………………………… 这段程序也许在编译器中没有办法通过,因为编译器可能会为我们消除一些隐患!在这里我们只是增加了一个记录原来内存地址的指针q,然后记录了原来的内存地址p,如果不幸的话,数据发生了移动,那么所记录的原来的内存地址q所指向的内存空间实际上已经放回到堆上了!这样一来,我们应该终于意识到问题的所在和可怕了吧! 3、返回情况 返回的是一个void类型的指针,调用成功。(这就再你需要的时候进行强制类型转换) 返回NULL,当需要扩展的大小(第二个参数)为0并且第一个参数不为NULL,此时原内存变成了“freed(游离)”的了。 返回NULL,当没有足够的空间可供扩展的时候,此时,原内存空间的大小维持不变。 4、特殊情况 如果mem_address为null,则realloc()和malloc()类似。分配一个newsize的内存块,返回一个指向该内存块的指针。 如果newsize大小为0,那么释放mem_address指向的内存,并返回null。 如果没有足够可用的内存用来完成重新分配(扩大原来的内存块或者分配新的内存块),则返回null.而原来的内存块保持不变。
更多文章:

incorporated翻译(谷歌翻译manufacturing incorporated的中文)
2025年2月28日 09:40

从技术层面看,公有云、私有云、混合云是分别什么意思?微软云计算提供了几种服务模式
2025年3月3日 03:10

compulsory翻译(把这句英语翻译成汉语【At. least. 38. should. be. compulsory)
2025年2月19日 13:00

php正则匹配中文(PHP正则提取中文部分内容,怎么实现呀)
2025年3月14日 06:50

bandizip有广告吗(Bandizip和WinRAR哪个好用)
2025年3月31日 03:10

javascriptjavascript教师(前端学习中 先学好javascript还是先学jquery框架)
2025年3月8日 06:40

数据库查询成绩排名前三(数据库考试查询微观经济学成绩前三名的学生信息,那个前三名怎么设置,急求)
2025年4月3日 05:30

腾讯云域名购买(腾讯云购买的域名,可以用于其他主机吗怎么做)
2025年2月9日 19:20