// Strvec.h
#pragma once
#include <iostream>
#include <string>
#include <memory>
#include <utility>
#include <initializer_list>
// 实现简版vector,之所以说简版是因为此vector只能存string,没有使用模板
class StrVec
{
public:
StrVec():elements(nullptr),first_free(nullptr),cap(nullptr){} // 默认构造函数,将指针初始化为空指针
StrVec(const StrVec& origin); // 拷贝构造函数
StrVec(const std::initializer_list<std::string>& strVec);
StrVec& operator=(const StrVec& strVec); // 拷贝赋值运算符
~StrVec(); // 析构函数
void push_back(const std::string& e);
size_t size() const { return first_free - elements; }; // 已存储元素的数量,因为无需改变数据成员,所以声明为cosnt
size_t capacity() const { return cap - elements; }; // 总内存大小
std::string* begin() const { return elements; };
std::string* end() const { return first_free; };
private:
std::allocator<std::string> alloc;
void chk_n_alloc() { if (size() == capacity())reallocate(); }; // 添加元素时使用
void reallocate(); // 重新分配内存
void free(); // 销毁元素并释放内存
// 工具函数,被构造拷贝函数,赋值运算符,析构函数使用
std::pair<std::string*, std::string*> alloc_n_copy(const std::string*, const std::string*);
std::string* elements;
std::string* first_free;
std::string* cap;
};
// StrVet.cpp
#include "StrVec.h"
// 这里是移动而不是拷贝元素
void StrVec::reallocate() // 重新分配内存
{
auto newSize = size() ? 2 * size() : 1;
auto newMem = alloc.allocate(newSize); // 新分配内存是原来的2倍
auto dest = newMem;
auto elem = elements;
while (elem != first_free)
{
alloc.construct(dest++, std::move(*elem++)); // 这里使用string的移动构造函数而不是拷贝构造函数,可以提高性能
}
free();
elements = newMem;
first_free = dest;
cap = elements + newSize;
}
void StrVec::free() // 销毁元素并释放内存
{
// 不能传递给deallocate一个空指针,要保证容器中有元素才进行销毁
if (elements)
{
for (auto p = first_free; p != elements;)
{
alloc.destroy(--p);
}
alloc.deallocate(elements, cap-elements);
}
}
// 工具函数,被构造拷贝函数,赋值运算符,析构函数使用
std::pair<std::string*, std::string*> StrVec::alloc_n_copy(const std::string* b, const std::string* e)
{
auto data = alloc.allocate(e - b);
return { data, std::uninitialized_copy(b, e, data) };
}
StrVec::StrVec(const StrVec& origin) // 拷贝构造函数
{
auto d = alloc_n_copy(origin.begin(), origin.end());
elements = d.first;
first_free = cap = d.second;
}
StrVec::StrVec(const std::initializer_list<std::string>& strvec)
{
size_t size = strvec.size();
auto data = alloc.allocate(2 * size);
auto dest = data;
auto elem = strvec.begin();
for (size_t i = 0; i < size; ++i)
{
alloc.construct(dest++, std::move(*elem++));
}
elements = data;
first_free = dest;
cap = elements + size;
}
StrVec& StrVec::operator=(const StrVec& strvec) // 拷贝赋值运算符
{
auto d = alloc_n_copy(strvec.begin(), strvec.end());
free(); // 释放原内存
elements = d.first;
first_free = cap = d.second;
return *this;
}
StrVec::~StrVec() // 析构函数
{
free();
}
void StrVec::push_back(const std::string& e)
{
chk_n_alloc(); // 保证有足够的空间添加元素
alloc.construct(first_free++, e); // 利用allocator的construct在已分配内存中构建新对象
}