13.5 动态内存管理类
类中管理动态的内存最好的方法是使用容器或者使用智能指针,但是可能如果我们自己要设计一套库,那么就需要让这个库的性能处于一个较好的水平。这个时候我们可能需要使用一些较为低层的管理内存的函数。
像vector这样的容器如果push的时候空间不足,贼会开辟新的空间,此时需要将原来的元素都拷贝到新的空间中去。
所以这里会调用拷贝构造函数,调用拷贝构造函数意味着需要消耗性能,那么有没有什么方法可以不调用拷贝构造函数。
我们可以使用移动构造函数,或者使用std::move()的关键,但是std::move(cls)其实也将调用传入的类型的移动构造函数。
关于具体move的细节在下一节。
练习
13.39
我分为了头文件和cpp文件。
对于resize()和reserve()我参考vector的准则。
对于resize(n)如果n大于capacity则重新分配内存。如果大于size(),则为后续添加的对象使用默认构造函数
如果小于size,则销毁最后size()-n个元素的元素。
对于reserve(n)如果,如果小于capacity()则什么都不做,如果大于capacity()则重新分配空间。
头文件
#pragma once
#include<string>
#include<memory>
using std::string;
class StrVec
{
public:
StrVec() :elements(nullptr),first_free(nullptr),cap(nullptr){
};
StrVec(const StrVec&);
StrVec & operator=(const StrVec&);
~StrVec();
void push_back(const std::string&);
size_t size()const {
return first_free - elements; };
size_t capacity()const {
return cap - elements; };
std::string* begin()const {
return elements; };
std::string* end()const {
return first_free; };
void reserve(size_t);
void resize(size_t);
private:
static std::allocator<string> alloc;
void chk_n_alloc() {
if (first_free==cap) {
reallocate();
}
};
std::pair<string*, string*> alloc_n_copy(const string*,const string*);
//释放内存
void free();
void reallocate();
//指向第一个元素
std::string *elements;
//指向最后一个元素的下一位置
std::string* first_free;
//指向空间最后的位置
std::string *cap;
};
cpp文件
#include "pch.h"
#include "StrVec.h"
#include<iostream>
using std::cout;
using std::endl;
std::allocator<string> StrVec::alloc;
StrVec::StrVec(const StrVec & vec)
{
//保存一样多的元素,所以first_free将会等于cap
auto data = alloc_n_copy(vec.begin(),vec.end());
elements = data.first;
first_free = cap = data.second;
}
StrVec & StrVec::operator=(const StrVec &vec)
{
//这里不用考虑容量,因为vec.end()是first_free的指针
auto data = alloc_n_copy(vec.begin(), vec.end());
free();
elements = data.first;
first_free = cap = data.second;
//cap = elements + vec.capacity();
// TODO: 在此处插入 return 语句
return *this;
}
StrVec::~StrVec()
{
free();
}
void StrVec::push_back(const