14.16
首先是StrBlob类
#ifndef STRBLOB_H_INCLUDED
#define STRBLOB_H_INCLUDED
#include <string>
#include <vector>
#include <initializer_list>
#include <memory>
#include <stdexcept>
using namespace std;
class StrBlobPtr;
class StrBlob{
//重载==
friend bool operator==(const StrBlob&, const StrBlob&);
//重载!=
friend bool operator!=(const StrBlob&, const StrBlob&);
public:
friend class StrBlobPtr;
typedef vector<string>::size_type size_type;
StrBlob();
StrBlob(initializer_list<string> il);
//拷贝构造函数
StrBlob(const StrBlob& a){
data = make_shared<vector<string>>(*a.data);
}
//拷贝赋值运算符
StrBlob& operator=(const StrBlob & a){
data =make_shared<vector<string>>(*a.data);
return *this;
}
size_type size() const{
return data->size();
}
bool empty(){
return data->empty();
}
//添加删除元素
void push_back(const string &t){
data->push_back(t);
}
void pop_back();
//访问元素
string & front();
const string & front ()const;
string & back();
const string & back ()const;
private:
shared_ptr<vector<string>> data;
//如果data[i]不合法,抛出一个异常
void check(size_type i,const string &msg) const;
StrBlobPtr begin();
StrBlobPtr end();
};
bool operator==(const StrBlob& a, const StrBlob& b){
return a.data == b.data;
}
bool operator!=(const StrBlob&a, const StrBlob&b){
return !(a.data == b.data);
}
class StrBlobPtr
{
public:
StrBlobPtr() :curr(0) {}
StrBlobPtr(StrBlob &a, size_t sz = 0) :wptr(a.data), curr(sz) {}
string& deref() const//显示当前指向的vector的元素
{
auto p = check(curr, "dereference past end");
return (*p)[curr];
}
StrBlobPtr& incr()//指针前移
{
check(curr, "increment past end of StrBlobPtr");
++curr;
return *this;
}
private:
std::shared_ptr<vector<string>> check(size_t i, const string &msg) const
{
auto ret = wptr.lock();//检查是否空链接,lock()返回空指针
if (!ret) throw std::runtime_error("unbound StrBlobPtr");//空链处理
if (i >= ret->size()) throw std::out_of_range(msg);//输出错误信息
return ret;//返回指针
}
std::weak_ptr<vector<string>> wptr;
size_t curr;
};
//构造函数
StrBlob::StrBlob():data(make_shared<vector<string>>()){}
StrBlob::StrBlob(initializer_list<string> il):data(make_shared<vector<string>>(il)){}
//检查容器内元素是否存在的方法
void StrBlob::check(size_type i,const string &msg)const{
if(i>=data->size()){
throw out_of_range(msg);
}
}
//访问元素的方法
string & StrBlob::front(){
//如果vector为空,check将会抛出异常
check(0,"front on empty Str");
return data->front();
}
const string & StrBlob::front ()const{
check(0,"front on empty Str");
return data->front();
}
string & StrBlob::back(){
check(0,"back on empty Str");
return data->back();
}
const string & StrBlob::back ()const{
check(0,"back on empty Str");
return data->back();
}
void StrBlob::pop_back(){
check(0,"pop_back on empty Str");
data->pop_back();
}
StrBlobPtr StrBlob::begin(){
return StrBlobPtr(*this);
}
StrBlobPtr StrBlob::end(){
auto ret = StrBlobPtr(*this,data->size());
return ret;
}
#endif // STRBLOB_H_INCLUDED
然后是StrblobPtr类
#ifndef STRBLOBPRE_H_INCLUDED
#define STRBLOBPRE_H_INCLUDED
#include <string>
#include <vector>
#include <initializer_list>
#include <memory>
#include <stdexcept>
#include "StrBlob.h"
using std::vector; using std::string;
class StrBlobPtr
{
//重载==
friend bool operator==(const StrBlobPtr&, const StrBlobPtr&);
//重载!=
friend bool operator!=(const StrBlobPtr&, const StrBlobPtr&);
public:
StrBlobPtr() :curr(0) {}
StrBlobPtr(StrBlob &a, size_t sz = 0) :wptr(a.data), curr(sz) {}
string& deref() const
{
auto p = check(curr, "dereference past end");
return (*p)[curr];
}
StrBlobPtr& incr()
{
check(curr, "increment past end of StrBlobPtr");
++curr;
return *this;
}
private:
std::shared_ptr<vector<string>> check(size_t i, const string &msg) const
{
auto ret = wptr.lock();
if (!ret) throw std::runtime_error("unbound StrBlobPtr");
if (i >= ret->size()) throw std::out_of_range(msg);
return ret;
}
std::weak_ptr<vector<string>> wptr;
size_t curr;
};
bool operator==(const StrBlobPtr&a, const StrBlobPtr&b){
return a.wptr == b.wptr;
}
bool operator!=(const StrBlobPtr&a, const StrBlobPtr&b){
return !(a.wptr == b.wptr);
}
#endif // STRBLOBPRE_H_INCLUDED
继续是StrVec类
#ifndef STRVEC_H_INCLUDED
#define STRVEC_H_INCLUDED
#include<memory>
#include<algorithm>
/**类似于vector内存分配策略的简化实现*/
class StrVec{
//重载==
friend bool operator==(const StrVec&, const StrVec&);
//重载!=
friend bool operator!=(const StrVec&, const StrVec&);
public:
StrVec(std::initializer_list<std::string> il);
StrVec(): elements(nullptr),first_free(nullptr),cap(nullptr){} //allocator成员进行默认初始化
StrVec(const StrVec&); //拷贝构造函数
StrVec &operator=(const StrVec&); //拷贝赋值运算符
~StrVec();
StrVec(StrVec &&s) noexcept; //移动构造函数
StrVec &operator=(StrVec &&rhs) noexcept;
void push_back(const std::string&); //拷贝元素
void push_back(std::string &&);
size_t size() const{ //长度
return first_free-elements;
}
size_t capacity() const {
return cap - elements;
}
std::string *begin()const{
return elements;
}
std::string *end()const{
return first_free;
}
private:
std::allocator<std::string> alloc;//分配元素
//被添加元素的函数与实用
void chk_n_alloc(){
if(size() == capacity()){
reallocate();
}
}
//工具函数 :被拷贝构造函数,赋值运算符和析构函数所使用
std::pair<std::string*,std::string*> alloc_n_copy(const std::string*,const std::string*);
void free(); //销毁元素并且释放内存
void reallocate(); //获得更多内存并且拷贝元素
std::string *elements; //指向数组首元素的指针
std::string *first_free; //指向数组第一个空闲元素的指针
std::string *cap; //指向数组尾后位置的指针
void alloc_n_move(size_t n); //申请n长的内存块
void reserve(size_t n); //分配至少能容下n个元素的内存空间
void resize(size_t n); //分配至少能容下n个元素的内存空间,空位置值初始化
};
//重载==
bool operator==(const StrVec&a, const StrVec&b){
auto aa = a.begin();
auto bb = b.begin();
while(aa!= a.end()&&bb!=b.end()){
if(*aa != *bb){
return 0;
}
}
return 1;
}
//重载!=
bool operator!=(const StrVec&a, const StrVec&b){
return !(a==b);
}
void StrVec::push_back(const std::string&s){
chk_n_alloc(); //确保有空间容纳新的元素
alloc.construct(first_free++,s); //在first_free指向的元素中构造s的副本
}
std::pair<std::string*,std::string*> StrVec::alloc_n_copy(const std::string *a , const std::string *e){
//分配空间保存给定范围中的元素
auto data = alloc.allocate(e-a);
//初始化并返回一个pair,该pair是有data和uninitialized_copy的返回值构成
auto llast = uninitialized_copy(a,e,data);
return {data,llast};
}
/**
void StrVec::free(){
//不能传递给deallocate一个空的指针,如果elements为0,函数什么也不做
if(elements){
for(auto p = first_free;p!=elements;){
alloc.destroy(--p);//先destory销毁元素
}
alloc.deallocate(elements,cap - elements);//释放元素占用的内存
}
}*/
void StrVec::free(){
if(elements){
for_each(elements,first_free,[this](std::string &s){alloc.destroy(&s);});
alloc.deallocate(elements,cap - elements);//释放元素占用的内存
}
}
StrVec::StrVec(const StrVec &s){
//调用alloc_n_copy分配空间以容纳与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){
//调用alloc_n_copy分配内存,大小与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++,std::move(*elem++));
}
free(); //转移完成后旧释放旧内存空间
//更新我们的数据结构
elements = newdata;
first_free = dest;
cap = elements+newcapacity;
}
*/
void StrVec::reallocate(){
auto newcapacity = size() ? 2*size() :1;
auto first = alloc.allocate(newcapacity);
auto last = std::uninitialized_copy(make_move_iterator(begin()),make_move_iterator(end()),first);
free();
elements = first;
first_free = last;
cap = elements+newcapacity;
}
//13.39
void StrVec::alloc_n_move(size_t n)
{
//申请n长的内存块
auto newdata = alloc.allocate(n);
//该内存块起始点
auto dest = newdata;
//指示旧元素地址的起始
auto elem = elements;
//在新内存挨个使用移动构造函数构造进新内存
for (size_t i = 0; i != size(); ++i)
alloc.construct(dest++, std::move(*elem++));
free();//构造完毕后释放旧内存
//更新当前StrVec属性
elements = newdata;
first_free = dest;
cap = elements + n;
}
void StrVec::reserve(size_t n)
{
if (n <= capacity()) return; //若是要求的内存长度小于当下长度,直接返回,什么也不做
alloc_n_move(n); //分配n个长度的空间
}
void StrVec::resize(size_t n){
if(n>size() ){//比当前大分两种情况,一种是比最大容量还要大,另一种是小于最大容量
if(n>capacity()){
reserve(2*n);
}
for(size_t i =size();i!=n;i++){
alloc.construct(first_free++," ");
}
}else if(n<size()){//比当前小就要从后往前一个个销毁
while(first_free!= elements+n){
alloc.destroy(first_free);
first_free--;
}
}
}
StrVec::StrVec(std::initializer_list<std::string> il){
auto newdata = alloc_n_copy(il.begin(),il.end());
elements = newdata.first;
first_free = cap = newdata.second;
}
//移动构造函数
StrVec::StrVec(StrVec &&s) noexcept:elements(s.elements),first_free(s.first_free),cap(s.cap){
//另s进入这样的状态-----对其运行析构函数是安全的
s.elements = s.first_free = s.cap = nullptr;
}
//移动赋值运算符
StrVec &StrVec::operator=(StrVec &&rhs) noexcept{
//首先检测自身赋值
if(this != &rhs){
free(); //释放已有元素
elements = rhs.elements; //从rhs接管资源
first_free = rhs.first_free;
cap = rhs.cap;
//将rhs置于可析构的状态
rhs.elements = rhs.first_free = rhs.cap = nullptr;
}
return *this;
}
void StrVec::push_back(std::string &&s){
chk_n_alloc(); //确保有空间容纳新的元素
alloc.construct(first_free++,std::move(s)); //在first_free指向的元素中构造s的副本
}
#endif // STRVEC_H_INCLUDED
最后是String
#ifndef STRING_H_INCLUDED
#define STRING_H_INCLUDED
#include <string>
#include <algorithm>
#include <memory>
#include <vector>
#include<iostream>
class String{
//重载<<
friend std::ostream& operator<<(std::ostream&, const String&);
//重载==
friend bool operator==(const String&, const String&);
//重载!=
friend bool operator!=(const String&, const String&);
public:
String():String(""){} //默认构造函数
String(const char *s){
auto s1 = const_cast<char*> (s); //const_cast的作用就是解const
for(;*s1;s1++){range_initializer(s, s1);} //计算字符长度
//申请内存
}
String(const String&);
String & operator=(const String& );
~String(){
free();
}
void free(){
if(elements){//若elements不为空
std::for_each(elements,first_free,[this](char &c){alloc.destroy(&c);});
alloc.deallocate(elements,first_free-elements);
}
}
//移动构造函数
String(String &&s) noexcept;
//移动构造运算符
String & operator=(String &&rhs) noexcept;
void range_initializer(const char*, const char*);
const char *c_str() const { return elements; }
private:
std::allocator<char> alloc; //用于申请内存
char *elements; //首指针
char *first_free; //尾后指针
std::pair<char*,char*> alloc_n_copy(const char *a,const char *b){
auto first_address = alloc.allocate(b-a); //返回申请内存的首指针
auto last_f_address = std::uninitialized_copy(a,b,first_address);//返回构造后的尾后指针
return {first_address,last_f_address}; //以pair的形式返回
}
};
//重载==
bool operator==(const String&a, const String&b){
char *aa = const_cast<char*>(a.c_str());
char *bb = const_cast<char*>(b.c_str());
while(aa&&bb){
if(*aa!=*bb){
return false;
}
}
return true;
}
//重载!=
bool operator!=(const String&a, const String&b){
return !(a==b);
}
void String::range_initializer(const char *first, const char *last)
{
auto newstr = alloc_n_copy(first, last);
elements = newstr.first;
first_free = newstr.second;
}
String::String(const String&s){
std::cout<<"拷贝构造函数"<<std::endl;
auto newStr = alloc_n_copy(s.elements,s.first_free);
elements = newStr.first;
first_free = newStr.second;
}
String& String::operator=(const String&a){
std::cout<<"拷贝赋值运算符"<<std::endl;
auto newc = alloc_n_copy(a.elements,a.first_free);
free();
elements = newc.first;
first_free = newc.second;
return *this;
}
//移动构造函数
String::String(String &&s) noexcept{
std::cout<<"移动构造函数"<<std::endl;
elements = s.elements;
first_free = s.first_free;
s.elements = s.first_free = nullptr;
}
//移动赋值运算符
String &String::operator=(String &&rhs) noexcept{
std::cout<<"移动赋值运算符"<<std::endl;
if(this!=&rhs){
free();
elements = rhs.elements;
first_free = rhs.first_free;
rhs.elements = rhs.first_free = nullptr;
}
return *this;
}
std::ostream& operator<<(std::ostream &os, const String &s)
{
char *c = const_cast<char*>(s.c_str());
while (*c)
os << *c++;
return os;
}
#endif // STRING_H_INCLUDED
14.17
有必要,book类不需要对编号进行比较
代码见14.5
14.18
StrBlob的<
bool operator<(const StrBlob&a, const StrBlob&b){
return a.size()<b.size();
}
StrBlobPtr的<
bool operator<(const StrBlobPtr & a, const StrBlobPtr & b){
auto ret1 = a.wptr.lock();
auto ret2 = a.wptr.lock();
if(ret1&&ret2){
return ret1->size()<ret2->size();
}else{
return false;
}
}
String的<
bool operator<(const String&a, const String&b){
auto size1 = a.first_free-a.elements;
auto size2 = b.first_free-b.elements;
return size1<size2;
}
StrVec的<
bool operator<(const StrVec&a, const StrVec&b){
return a.size()<b.size();
}
14.19
并不需要,找不到唯一逻辑可靠的<关系
14.20
Sales_data重载+=运算符
//实现+=运算符
Sales_data& Sales_data::operator+=(const Sales_data &rhs)
{
units_sold += rhs.units_sold;
revenue += rhs.revenue;
return *this;
}
Sales_data重载+运算符
//实现+运算符
Sales_data operator+(const Sales_data &lhs, const Sales_data &rhs)
{
Sales_data sum = lhs;//拷贝lhs到sum
sum += rhs;//进行对象的加法运算
return sum;//返回对象的合成移动拷贝(右值)
}
14.21
我上一题使用的是和以前一样的版本,也就是体现出优点的版本
若是单独定义+,会多使用一个Sales_data 的临时对象
14.22
使用一个单参构造即可
Sales_data& Sales_data::operator=(const std::string&x){
*this = Sales_data(x);
return *this;
}
14.23
两个重载=一起看
声明
StrVec &operator=(const StrVec&); //拷贝赋值运算符
StrVec & operator=(const std::initializer_list<std::string> il);
实现
StrVec &StrVec::operator=(const StrVec &rhs){
//调用alloc_n_copy分配内存,大小与rhs中元素占用空间一样多
auto data = alloc_n_copy(rhs.begin(),rhs.end());
free();
elements = data.first;
first_free = cap = data.second;
return *this;
}
StrVec::StrVec(std::initializer_list<std::string> il){
auto newdata = alloc_n_copy(il.begin(),il.end());
elements = newdata.first;
first_free = cap = newdata.second;
}
14.24
我用的book,每本书有唯一的编号,需要自己定义拷贝赋值运算符,具体略。。
14.25
无
14.26
StrVec的下标运算符
class StrVec{
public:
std::string &operator[](std::siez_t n) // 非常量版本
{ return elements[n]; }
const std::string &operator[](std::size_t n) const // 常量版本
{ return elements[n]; }
private:
std::string *elements; // 指向数组首元素的指针
};
StrBlob下标运算符
//定义下标运算符
std::string& operator[](int n){//普通对象使用
int i = 0;
for(auto c:*data){
i++;
if(i == n){
cout<<c<<endl;
}
}
}
const std::string& operator[](int n)const{//常量对象使用
int i = 0;
for(auto c:*data){
i++;
if(i == n){
cout<<c<<endl;
}
}
}
StrBlobPtr运算符
//定义下标运算符
std::string& operator[](int n){//普通对象使用
auto ret = wptr.lock();
if(ret){
int i = 0;
for(auto c:*ret){
i++;
if(i == n){
cout<<c<<endl;
}
}
}else{
cout<<"下标越界"<<endl;
}
}
const std::string& operator[](int n)const{//常量对象使用
auto ret = wptr.lock();
if(ret){
int i = 0;
for(auto c:*ret){
i++;
if(i == n){
cout<<c<<endl;
}
}
}else{
cout<<"下标越界"<<endl;
}
}
String的下标运算符
char & operator[](std::size_t n){//普通对象使用
return elements[n];
}
const char & operator[](std::size_t n) const {//常量对象使用
return elements[n];
}
14.27
实现了书上的版本
#ifndef STRBLOB_H_INCLUDED
#define STRBLOB_H_INCLUDED
#include <string>
#include <vector>
#include <initializer_list>
#include <memory>
#include <stdexcept>
#include<iostream>
using namespace std;
class StrBlobPtr;
class StrBlob{
//重载==
friend bool operator==(const StrBlob&, const StrBlob&);
//重载!=
friend bool operator!=(const StrBlob&, const StrBlob&);
//重载<
friend bool operator<(const StrBlob&, const StrBlob&);
public:
friend class StrBlobPtr;
typedef vector<string>::size_type size_type;
StrBlob();
StrBlob(initializer_list<string> il);
//拷贝构造函数
StrBlob(const StrBlob& a){
data = make_shared<vector<string>>(*a.data);
}
//拷贝赋值运算符
StrBlob& operator=(const StrBlob & a){
data =make_shared<vector<string>>(*a.data);
return *this;
}
size_type size() const{
return data->size();
}
bool empty(){
return data->empty();
}
//添加删除元素
void push_back(const string &t){
data->push_back(t);
}
void pop_back();
//访问元素
string & front();
const string & front ()const;
string & back();
const string & back ()const;
//定义下标运算符
std::string& operator[](int n){//普通对象使用
int i = 0;
for(auto c:*data){
i++;
if(i == n){
cout<<c<<endl;
}
}
}
const std::string& operator[](int n)const{//常量对象使用
int i = 0;
for(auto c:*data){
i++;
if(i == n){
cout<<c<<endl;
}
}
}
private:
shared_ptr<vector<string>> data;
//如果data[i]不合法,抛出一个异常
void check(size_type i,const string &msg) const;
StrBlobPtr begin();
StrBlobPtr end();
};
bool operator==(const StrBlob& a, const StrBlob& b){
return a.data == b.data;
}
bool operator!=(const StrBlob&a, const StrBlob&b){
return !(a.data == b.data);
}
bool operator<(const StrBlob&a, const StrBlob&b){
return a.size()<b.size();
}
class StrBlobPtr
{
//重载<
friend bool operator<(const StrBlobPtr&a, const StrBlobPtr&b);
public:
StrBlobPtr() :curr(0) {}
StrBlobPtr(StrBlob &a, size_t sz = 0) :wptr(a.data), curr(sz) {}
string& deref() const//显示当前指向的vector的元素
{
auto p = check(curr, "dereference past end");
return (*p)[curr];
}
StrBlobPtr& incr()//指针前移
{
check(curr, "increment past end of StrBlobPtr");
++curr;
return *this;
}
//定义下标运算符
std::string& operator[](int n){//普通对象使用
auto ret = wptr.lock();
if(ret){
int i = 0;
for(auto c:*ret){
i++;
if(i == n){
cout<<c<<endl;
}
}
}else{
cout<<"下标越界"<<endl;
}
}
const std::string& operator[](int n)const{//常量对象使用
auto ret = wptr.lock();
if(ret){
int i = 0;
for(auto c:*ret){
i++;
if(i == n){
cout<<c<<endl;
}
}
}else{
cout<<"下标越界"<<endl;
}
}
//定义前置自增自减运算符
StrBlobPtr& operator++();
StrBlobPtr& operator--();
//定义后置自增自减运算符
StrBlobPtr& operator++(int);
StrBlobPtr& operator--(int);
private:
std::shared_ptr<vector<string>> check(size_t i, const string &msg) const
{
auto ret = wptr.lock();//检查是否空链接,lock()返回空指针
if (!ret) throw std::runtime_error("unbound StrBlobPtr");//空链处理
if (i >= ret->size()) throw std::out_of_range(msg);//输出错误信息
return ret;//返回指针
}
std::weak_ptr<vector<string>> wptr;
size_t curr;
};
//构造函数
StrBlob::StrBlob():data(make_shared<vector<string>>()){}
StrBlob::StrBlob(initializer_list<string> il):data(make_shared<vector<string>>(il)){}
//检查容器内元素是否存在的方法
void StrBlob::check(size_type i,const string &msg)const{
if(i>=data->size()){
throw out_of_range(msg);
}
}
//访问元素的方法
string & StrBlob::front(){
//如果vector为空,check将会抛出异常
check(0,"front on empty Str");
return data->front();
}
const string & StrBlob::front ()const{
check(0,"front on empty Str");
return data->front();
}
string & StrBlob::back(){
check(0,"back on empty Str");
return data->back();
}
const string & StrBlob::back ()const{
check(0,"back on empty Str");
return data->back();
}
void StrBlob::pop_back(){
check(0,"pop_back on empty Str");
data->pop_back();
}
StrBlobPtr StrBlob::begin(){
return StrBlobPtr(*this);
}
StrBlobPtr StrBlob::end(){
auto ret = StrBlobPtr(*this,data->size());
return ret;
}
bool operator<(const StrBlobPtr & a, const StrBlobPtr & b){
auto ret1 = a.wptr.lock();
auto ret2 = a.wptr.lock();
if(ret1&&ret2){
return ret1->size()<ret2->size();
}else{
return false;
}
}
//前置++
StrBlobPtr& StrBlobPtr::operator++(){
//如果curr已经只指向了容器的末尾位置,则无法递增它
check(curr,"后越界");
++curr;
return *this;
}
//前置--
StrBlobPtr& StrBlobPtr::operator--(){
//如果curr已经只指向了容器的末尾位置,则无法递增它
--curr;
check(curr,"前越界");
return *this;
}
//后置++
StrBlobPtr& StrBlobPtr::operator++(int){
//此处无需检查有效性
StrBlobPtr ret = *this;
++*this;//使用前置++
return ret;//返回之前记录的对象
}
//后置--
StrBlobPtr& StrBlobPtr::operator--(int){
//此处无需检查有效性
StrBlobPtr ret = *this;
--*this;//使用前置--
return ret;//返回之前记录的对象
}
#endif // STRBLOB_H_INCLUDED
14.28
自我感觉书上版本即可。。。。(懒了)
14.29
自增自减都是要对对象本身进行修改的,使用const毫无意义啊








网友评论