16.58 为你的StrVec类添加emplace_back函数。
StrVec.h(注意,函数模板和模板成员函数的定义和声明要放在一起,通常都放在头文件中)
#ifndef STRVEC_H #define STRVEC_H #include<iostream> #include<string> #include<utility> #include<memory> #include<initializer_list> using namespace std; class StrVec { friend bool operator==(const StrVec&,const StrVec&); friend bool operator!=(const StrVec&,const StrVec&); public: StrVec():elements(nullptr),first_free(nullptr),cap(nullptr){} StrVec(const StrVec&); StrVec& operator=(const StrVec&); ~StrVec() noexcept; //重载 void push_back(const string&); void push_back(string&&); // emplace member covered in chapter 16 template <class... Args> void emplace_back(Args&&...); size_t size() const { return first_free-elements;} size_t capacity() const { return cap-elements;} string *begin() const {cout<<"begin"<<endl; return elements;} string *end() const { cout<<"end"<<endl; return first_free;} void reserve(size_t n); void resize(size_t n,string s=string()); StrVec(initializer_list<string> il) { auto newcapacity=il.size(); auto newdata=alloc.allocate(newcapacity); auto dest=newdata; auto elem=il.begin(); while(elem!=il.end()) alloc.construct(dest++,*elem); elements=newdata; first_free=cap=dest; } StrVec(StrVec &&s) noexcept :elements(s.elements),first_free(s.first_free),cap(s.cap) { s.elements=s.first_free=s.cap=nullptr; } StrVec& operator=(StrVec &&rhs) noexcept { if(this!=&rhs) { free(); elements=rhs.elements; first_free=rhs.first_free; cap=rhs.cap; rhs.elements=rhs.first_free=rhs.cap=nullptr; } return *this; } StrVec& operator=(initializer_list<string>); string& operator[](size_t n) { cout<<"[]"<<endl; return *(elements+n); } const string& operator[](size_t n) const { cout<<"const []"<<endl; return elements[n]; } private: static allocator<string> alloc; string *elements; string *first_free; string *cap; void chk_n_alloc() { if(size()==capacity()) reallocate(); } pair<string*,string*> alloc_n_copy(const string*,const string*); void free(); void reallocate(); }; bool operator==(const StrVec&,const StrVec&); bool operator!=(const StrVec&,const StrVec&); // emplace member covered in chapter 16 template <class... Args> inline void StrVec::emplace_back(Args&&... args) { chk_n_alloc(); // reallocates the StrVec if necessary alloc.construct(first_free++, std::forward<Args>(args)...); } #endif // STRVEC_H
StrVec.cpp
#include"StrVec.h" #include<algorithm> allocator<string> StrVec::alloc; StrVec::StrVec(const StrVec &s) { auto newdata=alloc_n_copy(s.begin(),s.end()); elements=newdata.first; first_free=newdata.second; cap=newdata.second; } StrVec& StrVec::operator=(const StrVec &s) { auto data=alloc_n_copy(s.begin(),s.end()); free(); elements=data.first; first_free=cap=data.second; return *this; } StrVec& StrVec::operator=(initializer_list<string> il) { auto data=alloc_n_copy(il.begin(),il.end()); free(); elements=data.first; first_free=cap=data.second; return *this; } StrVec::~StrVec() noexcept { free(); } void StrVec::push_back(const string &s) { chk_n_alloc(); alloc.construct(first_free++,s); } void StrVec::push_back(string&& s) { chk_n_alloc(); alloc.construct(first_free++,std::move(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_each(elements,first_free,[](string p) { alloc.destroy(&p);}); for_each(&elements,&first_free,[](string *p) { alloc.destroy(p);}); //for(auto p=first_free;p!=elements;) // alloc.destroy(--p); alloc.deallocate(elements,cap-elements); } } void StrVec::reallocate() { auto newcapacity=size()?2*size():1; auto newdata=alloc.allocate(newcapacity); auto dest=newdata; auto elem=elements; // auto last=uninitialized_copy(begin(),end(),newdata); //使用移动迭代器 //auto last=uninitialized_copy(make_move_iterator(begin()),make_move_iterator(end()),newdata); for(size_t i=0;i!=size();++i) alloc.construct(dest++,std::move(*elem++)); free(); elements=newdata; first_free=dest; cap=elements+newcapacity; } void StrVec::reserve(size_t n) { if(capacity()<n) reallocate(); } void StrVec::resize(size_t n,string s) { if(size()<n) push_back(s); else if(size()>n) { for(auto p=elements+n;p!=first_free;) alloc.destroy(p++); first_free=elements+n; } } bool operator==(const StrVec& lhs,const StrVec& rhs) { return lhs.elements==rhs.elements&&lhs.first_free==rhs.first_free&&lhs.cap==rhs.cap; } bool operator!=(const StrVec& lhs,const StrVec& rhs) { return !(lhs==rhs); }
main.cpp
#include <iostream> #include"StrVec.h" using namespace std; void print(const StrVec &svec) { cout<<"print"<<endl; for (auto it : svec) cout << it << " " ; cout <<endl; } int main() { StrVec vec; // empty StrVec string s = "some string or another"; vec.push_back(s); // calls push_back(const string&) vec.push_back("done"); // calls push_back(string&&) // emplace member covered in chpater 16 s = "the end"; vec.emplace_back("10"); // adds cccccccccc as a new last element vec.emplace_back(s); // uses the string copy constructor string s1 = "the beginning", s2 = s; vec.emplace_back(s1 + s2); // uses the move constructor print(vec); }
16.61定义你自己版本的make_shared。
#include<iostream> #include<memory> #include<string> using namespace std; template <typename T,typename... Args> shared_ptr<T>Make_shared(Args&&... args) { return make_shared<T>(std::forward<Args>(args)...); } int main() { auto p=Make_shared<int>(1); cout<<*p<<endl; auto pp=Make_shared<string>(10,'c'); cout<<*pp<<endl; }