头文件:
//
// Created by Administrator on 2020/11/20.
//
#ifndef CPPBASE_MYSTRVEC_H
#define CPPBASE_MYSTRVEC_H
#include <memory>
#include <utility>
#include <iostream>
using namespace std;
namespace MyStrVecSpace {
class MyStrVec {
public:
MyStrVec() : elements(nullptr), first_free(nullptr), cap(nullptr) {}
MyStrVec(std::initializer_list<string> list) : elements(nullptr), first_free(nullptr), cap(nullptr) {
auto p = alloc_n_copy(list.begin(), list.end());
elements = p.first;
first_free = cap = p.second;
}
MyStrVec(const MyStrVec &rhs);
MyStrVec(MyStrVec &&rhs);
MyStrVec &operator=(const MyStrVec &other);
// 重载初值列的赋值运算符
MyStrVec &operator=(std::initializer_list<string> list);
MyStrVec &operator=(MyStrVec &&rhs);
~MyStrVec();
// 下标运算符
string &operator[](std::size_t i) {
// return *(elements + i);
return elements[i];
}
const string &operator[](std::size_t i) const {
return *(elements + i);
}
void push_back(const string &str);
void push_back(string &&str);
std::size_t size() const { return first_free - elements; }
std::size_t capacity() const { return cap - elements; }
string *begin() const { return elements; }
string *end() const { return first_free; }
void print(const string &info) {
cout << info << ": ";
for (int i = 0; i < size(); ++i) {
cout << *(elements + i) << " ";
}
cout << endl;
}
private:
std::allocator<std::string> strVecAlloc; // 内存分配器,无法定义为static类型?与标准库中冲突?todo
void free(); // 释放空间
void reallocate(); // 分配更多内存并且拷贝元素
void chk_n_alloc(); // 检查是否还有空间能至少插入一个元素,如果没有调用reallocate分配
pair<string *, string *> alloc_n_copy(const string *s, const string *e); // 拷贝n个元素
pair<string *, string *> alloc_n_move_copy(const string *s, const string *e); // 移动拷贝n个元素
string *elements;
string *first_free;
string *cap;
};
// std::allocator<std::string> MyStrVec::strVecAlloc; // 内存分配器,无法定义为static类型?与标准库中冲突?todo
}
#endif //CPPBASE_MYSTRVEC_H
源文件:
//
// Created by Administrator on 2020/11/20.
//
#include "MyStrVec.h"
namespace MyStrVecSpace {
// 拷贝构造
MyStrVec::MyStrVec(const MyStrVec &rhs) {
auto p = alloc_n_copy(rhs.elements, rhs.first_free);
elements = p.first;
first_free = p.second;
cap = p.second;
}
// 移动构造
MyStrVec::MyStrVec(MyStrVec &&rhs) {
auto p = alloc_n_move_copy(rhs.elements, rhs.first_free);
elements = p.first;
first_free = p.second;
cap = p.second;
}
// 拷贝赋值
MyStrVec &MyStrVec::operator=(const MyStrVec &other) {
if (this == &other) {
return *this;
}
auto p = alloc_n_copy(other.begin(), other.end());
free();
elements = p.first;
first_free = cap = p.second;
return *this;
}
// 重载初值列的赋值运算符
MyStrVec &MyStrVec::operator=(std::initializer_list<string> list) {
auto p = alloc_n_copy(list.begin(), list.end());
free();
elements = p.first;
first_free = cap = p.second;
return *this;
}
// 移动赋值
MyStrVec &MyStrVec::operator=(MyStrVec &&other) {
if (this == &other) {
return *this;
}
auto p = alloc_n_move_copy(other.begin(), other.end());
free();
elements = p.first;
first_free = cap = p.second;
return *this;
}
// 析构
MyStrVec::~MyStrVec() {
free();
}
void MyStrVec::push_back(const string &str) {
chk_n_alloc(); // 确保有新空间容纳新元素
strVecAlloc.construct(first_free++, str);
}
void MyStrVec::push_back(string &&str) {
chk_n_alloc(); // 确保有新空间容纳新元素
strVecAlloc.construct(first_free++, std::move(str));
}
// 空间满后重新分配新空间并且移动构造元素到新空间,释放旧空间
void MyStrVec::chk_n_alloc() {
if (size() == capacity()) {
reallocate();
}
}
// 分配更多内存并且移动拷贝元素
void MyStrVec::reallocate() {
size_t newCap = size() ? 2 * size() : 1;
string *newDst = strVecAlloc.allocate(newCap);
string *newFree = newDst;
for (int i = 0; i < size(); ++i) {
strVecAlloc.construct(newFree++, std::move(*(elements + i))); // todo
}
// 重要,不要忘记释放旧空间
free();
// 更新指针
elements = newDst;
first_free = newFree;
cap = elements + newCap;
}
// 释放资源
void MyStrVec::free() {
if (elements) {
// 析构对象
for (int i = 0; i < size(); ++i) {
strVecAlloc.destroy(--first_free); // todo
}
// 释放内存
strVecAlloc.deallocate(elements, cap - elements);
}
}
// 拷贝构造n个元素
pair<string *, string *> MyStrVec::alloc_n_copy(const string *s, const string *e) {
auto p = strVecAlloc.allocate(e - s); // 分配新空间
return {p, uninitialized_copy(s, e, p)}; // 将元素拷贝到新空间中构造
}
// 移动构造n个元素
pair<string *, string *> MyStrVec::alloc_n_move_copy(const string *s, const string *e) {
auto p = strVecAlloc.allocate(e - s); // 分配新空间
return {p, uninitialized_copy(make_move_iterator(s), make_move_iterator(e), p)}; // 将元素移动到新空间中
}
}
测试:
// MyStrVec测试
void MyStrVecTest() {
// 初值列构造
MyStrVecSpace::MyStrVec sv({"HELLO", "WORLD"});
sv.print("sv");
// 初值列赋值
MyStrVecSpace::MyStrVec strvec;
strvec = {"hello", "world", "hello", "motherland"};
strvec.print("strvec");
auto &str1 = strvec[1];
str1 = "WORLD";
const string &str2 = strvec[1];
strvec.print("strvec");
MyStrVecSpace::MyStrVec strvec1;
strvec1.print("strvec1");
MyStrVecSpace::MyStrVec strvec2;
strvec2.print("strvec2");
strvec2.push_back("hello");
strvec2.push_back("word");
strvec2.push_back("hello");
strvec2.push_back("motherland");
strvec2.print("strvec2");
// 拷贝函数测试
MyStrVecSpace::MyStrVec strvec3(strvec2);
strvec3.print("strvec3");
strvec2 = strvec1;
strvec2.print("strvec2");
// 移动函数测试
MyStrVecSpace::MyStrVec strvec4(std::move(MyStrVecSpace::MyStrVec()));
strvec4.print("strvec4");
strvec4 = std::move(strvec1);
strvec4.print("strvec4");
return;
}
参考:C++ Primier 第五版中文版 第13章