动态内存管理类
内存管理类需要包括以下几个基本操作的正确性
- 添加元素:判断管理的空间大小是否能够添加新元素,如不够,则使用allocator分配内存,并将旧数据移动到新内存,然后释放旧内存,并更新内存首指针、第一个可用内存指针、尾指针位置。
- 对象拷贝:使用allocator的allocate分配内存,相关的uninitialized_copy拷贝元素到新的位置,并更新内存首指针、第一个可用内存指针、尾指针位置。
- 内存释放:使用allocator的destroy销毁内存,并使用deallocate执行内存回收操作
注意:静态对象必须首先在类外进行初始化操作。
//uninitialized_copy被编译器认为是不安全的,这语句是让编译器停止警告,放到第一行 #pragma warning(disable : 4996) #include<iostream> #include<string> #include<memory> using namespace std; class StrVec { public: StrVec() : elements(nullptr), first_free(nullptr), cap(nullptr) { } //拷贝构造函数 StrVec(const StrVec& s) { auto newdata = alloc_n_copy(s.begin(), s.end()); elements = newdata.first; first_free = cap = newdata.second; } //拷贝赋值运算 StrVec &operator=(const StrVec& 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 string& str) { chk_n_alloc(); //在first_free位置构造元素 alloc.construct(first_free++, str); } //输出内容 void print(ostream& os) { for (auto pos = begin(); pos != end(); pos++) os << *pos << endl; } size_t size() const { return first_free - elements; } size_t capacity() const { return cap - elements; } string* begin() const { return elements; } string* end() const { return first_free; } private: static allocator<string> alloc; void chk_n_alloc() { if (size() == capacity()) reallocate(); } //工具函数,被拷贝构造函数、赋值运算符和析构函数使用 std::pair<string*, string*>alloc_n_copy(const string*b, const string*e) { auto data = alloc.allocate(e - b); return{ data,uninitialized_copy(b,e,data) }; } //销毁元素,释放内存 void free() { //不能传递给一个空指针,为0什么也不做 if (elements) { for (auto p = first_free; p != elements;) alloc.destroy(--p); alloc.deallocate(elements, cap - elements); } } //获得更多内存,拷贝已有元素 void reallocate() { //分配两倍内存 auto newcapacity = size() ? 2 * size() : 1; //分配新内存 auto newdata = alloc.allocate(newcapacity); //数据从旧内存移动到新内存 auto dest = newdata;//指向新内存中下一个可用位置 auto elem = elements;//旧内存中下一个位置 for (size_t i = 0; i != size(); i++) //移动的时候,通过move函数转换为右值引用,使用了移动构造函数构造对象 alloc.construct(dest++, std::move(*elem++)); free();//移动完成,释放旧内存 //更新数据结构,换到新元素 elements = newdata; first_free = dest; cap = elements + newcapacity; } //指向数组首元素指针 string *elements; //指向数组第一个空闲元素的指针 string *first_free; //指向数组尾后位置 string *cap; }; allocator<string> StrVec::alloc;
使用时
int main() { { StrVec strVec; strVec.push_back("asdfasdf"); //strVec.push_back("123456"); //strVec.push_back("!@#$%^&"); //strVec.push_back("123123!@#$%^&"); auto strVec1 = strVec; strVec1.push_back("!@#$%^&"); strVec.print(cout); strVec1.print(cout); } _CrtDumpMemoryLeaks(); }