/* StrVec.h */ #ifndef _STRVEC_H_ #define _STRVEC_H_ #include <memory> #include <string> #include <vector> #include <utility> class StrVec { public: StrVec() : first(nullptr), last_end(nullptr), cap(nullptr){} StrVec(const StrVec&); StrVec& operator = (const StrVec&); ~StrVec (); void push_back(std::string&); size_t size(){ return (last_end - first); } size_t capacity(){ return (cap - first);} std::string* begin() const { return first; } std::string* end() const { return last_end; } private: static std::allocator<std::string> alloc; // 分配元素 std::string* first; // first element pointer(begin()) std::string* last_end; // last_end element pointer(end()) std::string* cap; // capacity pointer std::pair<std::string*, std::string*> alloc_n_copy (const std::string*, const std::string*); void chk_n_alloc (){ if (size() == capacity()) reallocate(); } void free (); void reallocate (); }; #endif // _STRVEC_H_
#include "StrVec.h" StrVec::StrVec(const StrVec& s){ auto newData = alloc_n_copy(s.begin(), s.end()); first = newData.first; last_end = cap = newData.second; } StrVec& StrVec::operator=(const StrVec& s){ auto data = alloc_n_copy(s.begin(), s.end()); free(); first = data.first; last_end = cap = data.second; return *this; } StrVec::~StrVec(){ free(); } void StrVec::push_back(std::string& str){ chk_n_alloc(); alloc.construct(last_end++, str); } std::pair<std::string*, std::string*> StrVec::alloc_n_copy(const std::string* begin, const std::string* end){ auto data = alloc.allocate(end - begin); return {data, uninitialized_copy(begin, end, data)}; } void StrVec::free(){ if (nullptr != first){ for (auto p = last_end; p >= first;) alloc.destroy(--p); alloc.deallocate(first, cap - first); } } void StrVec::reallocate(){ size_t newSize = size() * 2; auto newdata = alloc.allocate(newSize); auto dest = newdata; auto fst = first; // move the old elements for (size_t i = 0; i != size(); ++i) alloc.construct(dest++, std::move(*fst++)); free(); first = newdata; last_end = dest; cap = first + newSize; }
当使用allcator重新分配内存时,我们应该移动原来的数据而不是拷贝,如果有大量的数据,拷贝会非常浪费时间和空间资源,因此我们用到了标准库函数std::move,它定义在有文件 <utility>中。