vector 简单实现(未用到模板类,元素类型只能为string)
// 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在已分配内存中构建新对象 }