/* 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>中。