练习13.41
在push_back中我们为什么在construct调用后置递增
::因为first_free指针就是第一个空闲位置,使用前置每次插入都会隔一个位置
练习13.42
在你的textQuery和Queryresult类中用strvec代替vector<string>进行测试
::用StrVec替换vector<string>测试即可
练习13.43
重写free成员,用for_each和lambda来代替for循环destroy元素,你倾向于哪个?
::倾向于for_each,更好看
inline void StrVec::free() { if (elements) { for_each (elements,first_free,alloc.destroy ) alloc.deallocate(elements, cap - elements); } }
练习13.44
编写标准库string类的简化版本,命名为String。你的类应该至少有一个默认构造函数和一个接受c风格的字符串指针参数的构造函数,使用allocator为你的String类分配所需内存
#include <memory> #include <memory> using namespace std; class String{ public: String():elements(nullptr),first_free(nullptr),cap(nullptr){ } String(const String& s){ auto data=alloc_ncopy(s.begin(),s.end()); elements=data.first; first_free=cap=data.second; } String& operator=(const String&s){ auto data=alloc_ncopy(s.begin(),s.end()); free(); elements=data.first; first_free=cap=data.second;} ~String(){free();} String(const char*a,const char*b) { auto data=alloc_ncopy(a,b); elements=data.first; first_free=cap=data.second; } void push_back(char&c){check();alloc.construct(first_free++,c); } size_t size()const{return first_free-elements;} size_t capacity(){return cap-elements; } char* begin()const{return elements; } char* end()const{return first_free; } private: static allocator<char> alloc; char* elements; char* first_free; char* cap; void check(){if(size()==capacity())reallocate();} pair<char*,char*> alloc_ncopy(const char*a,const char*b){ auto data=alloc.allocate(b-a); return {data,uninitialized_copy(a,b,data)}; } void reallocate() { size_t newcapacity = size() ? 2 * size() : 1; char* newdata =alloc.allocate(newcapacity); char*dest=newdata; char*elem = elements; for (size_t i = 0; i != size(); ++i) alloc.construct(dest++, *elem++); free(); elements=newdata; first_free = dest; cap = elements + newcapacity; } void free() { if (elements) { for (char*p = first_free; p != elements; ) alloc.destroy(--p); alloc.deallocate(elements, cap - elements); } } }; allocator<char> String::alloc;
练习13.45
解释右值引用和左值引用的区别
::可以这样理解右值是值,左值是地址,所以分别是对值的引用和对地址的引用,不过右值引用和左值引用都是左值
练习13.46
什么类型的引用可以绑定到下面的初始化器上?
int f();
vector<int> vi(100);
int&& r1=f();
int& r2=vi[0];
int& r3=r1;
int&& r4=vi[0]*f();
练习13.47
对你在练习13.44中定义的String类,为它的拷贝构造函数和拷贝赋值运算符添加一条语句,打印一条信息
String(const String& s){ auto data=alloc_ncopy(s.begin(),s.end()); elements=data.first; first_free=cap=data.second; cout<<"拷贝构造"<<endl; } String& operator=(const String&s){ auto data=alloc_ncopy(s.begin(),s.end()); free(); elements=data.first; first_free=cap=data.second; cout<<"赋值运算"<<endl;}
练习13.48
定义一个vector<String>并在其上多次调用push_back,观察拷贝构造调用次数。
::每当vector内存满了要push_back,就会重新分配等于自身两倍的内存,并将已有的元素拷贝过去。