標籤:
13.39 編寫你自己版本的StrVec,包括自己版本的reserve,capacity(參見9.4節,第318頁)和resize(參見9.3.5節,第314頁)
13.40 為你的StrVec類添加一個建構函式,它接受一個initializer_list<string>參數
這是StrVec.h
#pragma once#include<string>#include<memory>#include<initializer_list>using namespace std;class StrVec{public: StrVec(): elements(nullptr),first_free(nullptr),cap(nullptr){} StrVec(initializer_list<string> iLStr);//建構函式,接受一個initializer_list<string>參數 StrVec(const StrVec&); StrVec& operator=(const StrVec&); ~StrVec(); string& operator[](size_t n)const //重載下標運算子,用來實現TextQuery和QueryResult對StrVec的使用 { return *(elements + n); } void push_back(const string&); size_t size()const { return first_free - elements; } size_t capacity()const { return cap - elements; } string *begin()const { return elements; } string *end()const { return first_free; } void reserve(size_t n);//分配至少容納n個元素的空間 void resize(size_t n);//調整容器的大小為n個元素。若n<size(),則多出的元素被丟棄 //若必須添加新元素,對新元素進行值初始化 void resize(size_t n,string str);//調整容器的大小為n個元素,任何新添加的元素都初始化為值strprivate: allocator<string> alloc; void chk_n_alloc() { if (size() == capacity()) reallocate(); } pair<string*, string*>alloc_n_copy(const string *, const string *); void free(); void reallocate(); string *elements; string *first_free; string *cap;};void StrVec::push_back(const string &s){ chk_n_alloc(); alloc.construct(first_free++, s);}pair<string*,string*>StrVec::alloc_n_copy(const string *b, const string *e){ auto data = alloc.allocate(e - b); return{ data,uninitialized_copy(b,e,data) };}void StrVec::free(){ if (elements) { for (auto p = first_free;p != elements;) alloc.destroy(--p); alloc.deallocate(elements, cap - elements); }}StrVec::StrVec(const StrVec &s){ auto newdata = alloc_n_copy(s.begin(), s.end()); elements = newdata.first; first_free = cap = newdata.second;}StrVec::~StrVec() { free(); }StrVec &StrVec::operator=(const StrVec &rhs){ auto data = alloc_n_copy(rhs.begin(), rhs.end()); free(); elements = data.first; first_free = cap = data.second; return *this;}void StrVec::reallocate(){ auto newcapacity = size() ? 2 * size() : 1; auto newdata = alloc.allocate(newcapacity); auto dest = newdata; auto elem = elements; for (size_t i = 0;i != size();++i) alloc.construct(dest++, move(*elem++)); free(); elements = newdata; first_free = dest; cap = elements + newcapacity;}void StrVec::reserve(size_t n)//分配至少容納n個元素的空間{ if (n > capacity())//如果n大於capacity()才會從新分配空間 { auto newdata = alloc.allocate(n);//重新分配n個空間,newdata為新分配的空間的首地址 auto dest = newdata; auto elem = elements; for (;elem != first_free;) //為新分配的空間調用construct來實現string的構造,採用move調用的是移動建構函式 alloc.construct(dest++, move(*(elem++))); free(); //元素的移動完成,釋放原有的空間 elements = newdata; //為指標賦予新的值 first_free = dest; cap = elements + n; } else return;}void StrVec::resize(size_t n)//調整容器的大小為n個元素。若n<size(),則多出的元素被丟棄 //若必須添加新元素,對新元素進行值初始化{ if (n <= size()) //如果n<size()則,應該對n後面的所有已經構造的元素調用destroy(),即多出的元素被丟棄 { for (;first_free != elements + n;) alloc.destroy(--first_free); } else { if (n > capacity()) { reserve(n); //因為n>capacity(),所以一定會分配新的空間 } for (;first_free != elements + n;) //添加新的元素,對新的元素進行值初始化 alloc.construct(first_free++, string("")); }}void StrVec::resize(size_t n,string str)//調整容器的大小為n個元素,任何新添加的元素都初始化為值str { if (n <= size()) //如果n<size()則,應該對n後面的所有已經構造的元素調用destroy(),即多出的元素被丟棄 { for (;first_free != elements + n;) alloc.destroy(--first_free); } else { if (n > capacity()) { reserve(n); //因為n>capacity(),所以一定會分配新的空間 } for (;first_free != elements + n;) //添加新的元素為str alloc.construct(first_free++, str); }}StrVec::StrVec(initializer_list<string> iLStr)//建構函式,接受一個initializer_list<string>參數{ auto newdata = alloc_n_copy(std::begin(iLStr), std::end(iLStr));//調用alloc_n_copy函數,返回一個pair<string*,string*> elements = newdata.first; //pair的第一個元素為新分配空間的地址 first_free = cap = newdata.second; //pair的第二個元素為新分配空間的最後一個元素之後的地址}
下面是主函數,用來驗證程式的正確性
// 13.5.cpp : 定義控制台應用程式的進入點。//#include "stdafx.h"#define _SCL_SECURE_NO_WARNINGS#include"StrVec.h"#include<string>#include<iostream>#include<memory>using namespace std;int main(){ StrVec sv({ "li","dandan","is" }); cout << sv.size() << " " << sv.capacity() << endl; sv.resize(5, "handsome"); cout << sv.size() << " " << sv.capacity() << endl; sv.resize(3); cout << sv.size() << " " << sv.capacity() << endl; sv.resize(6); cout << sv.size() << " " << sv.capacity() << endl; sv.reserve(20); sv.push_back("handsome"); cout << sv.size() << " " << sv.capacity() << endl; return 0;}
C++primer 練習13.39