动态内存管理
之前我们讲述过动态内存的开辟,可以通过new, malloc,以及alloc等方式,本文通过介绍alloc方式,构造一个StrVec类,这个类的功能类似于一个vector,实现字符串的管理,其中包含push一个字符串,动态扩容,析构,回收内存等操作。
StrVec类实现细节
StrVec类实现如下
1 | class StrVec |
1 elements成员,该成员指向StrVec内部数组空间的第一个元素
2 first_free成员指向第一个空闲元素,也就是有效元素的下一个元素,该元素开辟空间但未构造。
3 cap 指向最后一个元素的下一个位置。
4 alloc为静态成员,主要负责string类型数组的开辟工作。
5 无参构造函数将三个指针初始化为空,并且默认够早了alloc。
6 alloc_n_copy私有函数的功能是将一段区域的数据copy到新的空间,
并且返回新开辟的空间地址以及第一个空闲元素的地址(第一个未构造元素的地址)。
7 chk_n_alloc私有函数检测数组大小是否达到容量,如果达到则调用reallocate重新开辟空间。
8 reallocate重新开辟空间
9 capacity返回总容量
10 size返回元素个数
11 push_back 将元素放入开辟的类似于数组的连续空间中。
12 begin返回首元素地址
13 end返回第一个空闲元素地址,也是最后一个有效元素的下一个位置
无论我们实现push操作还是拷贝构造操作,都要实现realloc,当空间不足时要开辟空间将旧数据移动到新的数据
1 | //重新开辟空间 |
reallocate函数内部判断是否为刚初始化指针却没开辟空间的空数组,如果是则开辟1个大小的空间。
否则则开辟原有空间的两倍,将旧数据移动到新空间,采用了std::move操作,这么做减少拷贝造成的性能开销。
move之后原数据就无效了,所以要调用私有函数free()进行释放。我们实现该free操作
1 | //释放操作 |
先通过遍历destroy销毁内存,从而调用string的析构函数,最后在deallocate回收内存。
1 | // copy指定范围的元素到新的内存中,返回新元素的地址和第一个空闲元素地址的pair |
这样利用alloc_n_copy,我们就可以实现拷贝构造和拷贝赋值了
1 | //拷贝构造函数 |
但是拷贝赋值要注意一点,就是自赋值的情况,所以我们提前判断是否为自赋值,如不是则进行和拷贝构造相同的操作
1 | //拷贝赋值运算符 |
我们可以利用free实现析构函数
1 | //析构 |
接下来我们实现push_back,将指定字符串添加到数组空间,以及抛出元素
1 | //添加元素 |
接下来实现测试函数,测试上述操作
1 | void test_strvec() |
在主函数调用上面test_strvec,运行稳定。
总结
本文通过allocator实现了一个类似于vector的类,管理string变量。演示了拷贝构造,拷贝赋值要注意的事项,同时演示了如何手动开辟内存并管理内存空间。
源码链接
https://gitee.com/secondtonone1/cpplearn
想系统学习更多C++知识,可点击下方链接。
C++基础