13.1
拷贝构造函数:参数为该对象类型的引用,而且额外参数都带有默认值/或无额外参数
声明一个对象、该对象初始化内容为另一个对象的副本时:
class A;
A fun(A a) //拷贝构造函数
{
return a; 拷贝构造函数
}
A a1;
A a2(a1); //拷贝构造函数
A a3=a2; //拷贝构造函数
fun(a1);
13.2
当我们调用Sales_data(Sales_data rhs);构建对象时,例如:
Sales_data s1;
Sales_data s2(s1);//死循环
首先使用s1作为实参构建rhs,然后为了构建对象形参rhs,使用传递给rhs的参数来构建rhs调用的构造函数的形参,然后为了构建.....
所以该函数一直在构建这个构造函数的形参,而出来都没有进入函数体
13.3
复制StrBlob时,StrBlob的智能指针成员的计数(use_count)+1
复制StrBlobPtr时,由于成员是weak_ptr:指向智能指针的对象,所以Shared_ptr的计数不会有变化
13.4
Point global;
Pint foo_bar(Point arg)//1 arg
{ //2 local
Point local = arg, *heap = new Point(global);//3 heap指向的对象
*heap = local;
Point pa[4]={ local, *heap };//4 5 pa[0] pa[1]
return *heap;//6 函数返回值
}
13.5
class HasPtr
{
std::string *ps;
int i;
public:
HasPtr(const std::string &s = std::string()) :ps(new std::string(s)), i(0){}
HasPtr(HasPtr &hp) :ps(new std::string(*hp.ps)), i(hp.i)
{}
};
13.6
就是对象的函数运算符:operator=
对象与对象之间的赋值时
拷贝所有非static的数据成员,使用数据成员的各自拷贝赋值运算符
当该类型没有定义时
13.7
会复制数据成员shred_ptr,使其计数增加
因为是weak_ptr,所以不会改变计数
13.8
class HasPtr
{
std::string *ps;
int i;
public:
HasPtr(const std::string &s = std::string()) :ps(new std::string(s)), i(0){}
HasPtr(HasPtr &hp) :ps(new std::string(*hp.ps)), i(hp.i)
{}
HasPtr &operator=(const HasPtr &hp)
{
if (hp.ps==ps)
return *this;
delete ps;
ps = new std::string(*hp.ps);
i = hp.i;
return *this;
}
};
13.9
是一个成员函数,由符号"~"作为开头,紧接着类型名:~A();
完成函数体后释放调用对象所有非static数据成员
未定义时
13.10
调用StrBlob的合成析构函数释放数据成员,shared_ptr调用自己的析构函数,使计数-1
调用StrBlobPtr的合成析构函数,weak_ptr调用自己的析构函数
13.11
class HasPtr
{
std::string *ps;
int i;
public:
HasPtr(const std::string &s = std::string()) :ps(new std::string(s)), i(0){}
HasPtr(HasPtr &hp) :ps(new std::string(*hp.ps)), i(hp.i)
{}
HasPtr &operator=(const HasPtr &hp)
{
if (hp.ps == ps)
return *this;
delete ps;
ps = new std::string(*hp.ps);
i = hp.i;
return *this;
}
~HasPtr()
{
delete ps;
}
};
13.12
3次,形参accum,局部对象item1、item2在离开作用域后调用自己的析构函数
13.13
using namespace std;
struct x
{
x(){ cout << "x()" << endl; }
x(const x &_x){ cout << "x(const x &_x)" << endl; }
x &operator=(const x &_x){
cout << "operator=(const x &_x)" << endl;
return *this;
}
~x(){ cout << "~x()" << endl; }
};
void show(x _x)
{
cout << "show(x _x)" << endl;
}
int main()
{
x x1, x2(x1); //x() x(const x &)
x x3 = x2; //x(const x &)
x1 = x2; //operator=(const x &) x1.oerator=(x2)
x *x4 = new x(x1); //x(const x &) x _x=x1
vector<x> vec;
vec.push_back(x1); //x(const x &) x _val=x1
delete x4; //~x()
show(x1); //x(const x &) x _x=x1
system("pause");
return 0;
}
13.14
都是相同的,因为生成唯一序号的是默认构造函数,这里只有在声明a时使用
13.15
会改变,因为调用函数f(numbered s) 时和定义b、c时会使用拷贝构造函数构建对象
输出都不与a、b、c相同
13.16
会,因为传递的是引用,所以调用f()的输出不会有变化
13.17
略,自己看着办
13.18
class Employee
{
std::string name;
static int _id;
int id;
public:
Employee()
{
id = ++_id;
}
Employee(const std::string &n) :name(n)
{
id = ++id;2
}
};
int Employee::_id = 0;
13.19
不需要,员工是唯一的,不可能存在多个副本,所以应该让拷贝构造函数定义为delete:
Employee(const std::string &n) =delete;
13.20
会对数据成员对象指向相应的操作
13.21
不需要,因为他们使用智能指针来管理动态内存,当他们的对象调用析构函数时会对智能指针成员调用其析构函数。
13.22
class HasPtr
{
std::string *ps;
int i;
public:
HasPtr(const std::string &s = std::string()) :ps(new std::string(s)), i(0){}
HasPtr(HasPtr &hp) :ps(new std::string(*hp.ps)), i(hp.i)
{}
HasPtr &operator=(const HasPtr &hp)
{
if (hp.ps == ps)
return *this;
delete ps;
ps = new std::string(*hp.ps);<span style="white-space:pre"> </span>//拷贝值而不是地址
i = hp.i;
return *this;
}
~HasPtr()
{
delete ps;
}
};
13.23
书中假设自复制的情况需要额外的话费(分配内存)
13.24
数据成员ps指向的内存无法释放
编译器将提供合成的拷贝构造函数,那么只能复制指针的的地址,会造成多次delete成员ps指向的地址
13.25
拷贝构造函数和拷贝赋值运算符应该为调用对象动态分配内存,而不是与实参共享
因为使用的是智能指针,离开作用域时如果计数use_count为0会自动释放内存,合成的析构函数可以做到这点
13.26
using namespace std;
class ConstStrBlobPtr;
class StrBlob
{
shared_ptr<vector<string>> data;
void check(vector<string>::size_type i, const string &msg)const
{
if (i >= data->size())
throw out_of_range(msg);
}
public:
using size_type = vector<string>::size_type;
friend class ConstStrBlobPtr;
ConstStrBlobPtr begin()const;
ConstStrBlobPtr end()const;
StrBlob() :data(make_shared<vector<string>>()){}
StrBlob(initializer_list<string> il) :data(make_shared<vector<string>>(il)){}
StrBlob(const StrBlob &sb) :data(make_shared<vector<string>>(sb.data)){} //copy
StrBlob &operator=(const StrBlob &sb) //复制sb的data内容,并返回自己
{
data = make_shared<vector<string>>(sb.data);
return *this;
}
size_type size()const{ return data->size(); }
bool empty()const{ return data->empty(); }
void push_back(const string &str){ data->push_back(str); }
void pop_back()
{
check(0, "pop_back on empty StrBlob");
data->pop_back();
}
string &front()
{
check(0, "front on empty StrBlob");
return data->front();
}
string &back()
{
check(0, "back on empty StrBlob");
return data->back();
}
const string &front()const
{
check(0, "front on empty StrBlob");
return data->front();
}
const string &back()const
{
check(0, "back on empty StrBlob");
return data->back();
}
};
class ConstStrBlobPtr
{
weak_ptr<vector<string>> wptr;
size_t curr;
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;
}
public:
ConstStrBlobPtr() :curr(0) { }
ConstStrBlobPtr(const StrBlob &a, size_t sz = 0) :wptr(a.data), curr(sz) { }
bool operator!=(ConstStrBlobPtr& p) { return p.curr != curr; }
const string& deref() const
{
auto p = check(curr, "dereference past end");
return (*p)[curr];
}
ConstStrBlobPtr &incr()
{
check(curr, "increment past and of StrBlobPtr");
++curr;
return *this;
}
};
ConstStrBlobPtr StrBlob::begin()const
{
return ConstStrBlobPtr(*this);
}
ConstStrBlobPtr StrBlob::end()const
{
return ConstStrBlobPtr(*this, data->size());
}
13.27
class HasPtr
{
std::string *ps;
int i;
std::size_t *use; //对象计数记录
public:
HasPtr() :ps(new std::string()), i(0), use(new std::size_t(1)){}
HasPtr(const HasPtr &hp) :ps(hp.ps), i(hp.i), use(hp.use)
{
++*use;
}
HasPtr &operator=(HasPtr &hp)
{
if (ps == hp.ps)
{
++*use;
return *this;
}
++*hp.use;
if (!--*use)
{
delete ps;
delete use;
}
ps = hp.ps;
i = hp.i;
use = hp.use;
return *this;
}
~HasPtr()
{
if (!--*use)<span style="white-space:pre"> </span>//没有对象引用
{
delete ps;
delete use;
}
}
};
13.28
using namespace std;
class TreeNode
{
string value;
int *count;
TreeNode *left;
TreeNode *right;
public:
TreeNode() :count(new int(1)), left(nullptr), right(nullptr){}
TreeNode(const TreeNode &tn) :count(tn.count), left(tn.left), right(tn.right){ ++*count; }
TreeNode &operator=(TreeNode &tn)
{
auto temp = new TreeNode(tn);
++*tn.count;
if (!--*count)
{
if (left)
{
delete left;
left = nullptr;
}
if (right)
{
delete right;
right = nullptr;
}
delete count;
count = nullptr;
}
value = tn.value;
count = tn.count;
left = tn.left;
right = tn.right;
return *this;
}
~TreeNode()
{
if (!--*count)
{
if (left)
{
delete left;
left = nullptr;
}
if (right)
{
delete right;
right = nullptr;
}
delete count;
count = nullptr;
}
}
};
class BinStrTree
{
TreeNode *root;
public:
BinStrTree() :root(new TreeNode()){}
BinStrTree(const BinStrTree &bs) :root(bs.root){}
BinStrTree &operator=(BinStrTree &bs)
{
if (root = bs.root)
return *this;
delete root;
root = bs.root;
return *this;
}
~BinStrTree()
{
delete root;
}
};
13.29
HasPtr类中的swap函数成员使用 using std::swap声明,所以会匹配对应的版本,而不是只是用类中的swap。
13.30
class HasPtr
{
std::string *ps;
int i;
std::size_t *use;
public:
HasPtr(const std::string &s = std::string()) :ps(new std::string(s)), i(0), use(new std::size_t(1)){}
HasPtr(const HasPtr &hp) :ps(hp.ps), i(hp.i), use(hp.use)
{
++*use;
}
friend void swap(HasPtr &hp1, HasPtr &hp2);
HasPtr &operator=(HasPtr hp)
{
swap(*this, hp);
return *this;
}
~HasPtr()
{
if (!--*use)
{
delete ps;
delete use;
}
}
};
void swap(HasPtr &hp1, HasPtr &hp2)
{
using std::swap;
swap(hp1.ps, hp2.ps); //交换指针ps
swap(hp1.i, hp2.i); //交换值i
}
int main()
{
using namespace std;
vector<HasPtr> vec;
string temp;
while (cin>>temp)
{
vec.push_back(HasPtr(temp));
}
sort(vec.begin(), vec.end());
for (auto &x : vec)
cout << x << endl;
system("pause");
return 0;
}
13.31
class HasPtr
{
std::string *ps;
int i;
std::size_t *use;
public:
HasPtr(const std::string &s = std::string()) :ps(new std::string(s)), i(0), use(new std::size_t(1)){}
HasPtr(const HasPtr &hp) :ps(hp.ps), i(hp.i), use(hp.use)
{
++*use;
}
friend void swap(HasPtr &hp1, HasPtr &hp2);
HasPtr &operator=(HasPtr hp)
{
swap(*this, hp);
return *this;
}
bool operator<(const HasPtr &hp)
{
if (ps->size() < hp.ps->size())
return true;
else if (ps->size() == hp.ps->size())
{
return *ps < *hp.ps;
}
else
return false;
}
friend std::ostream &operator<<(std::ostream &os, const HasPtr &hp);
~HasPtr()
{
if (!--*use)
{
delete ps;
delete use;
}
}
};
void swap(HasPtr &hp1, HasPtr &hp2)
{
using std::swap;
std::cout << "hp1:\t" << *hp1.ps << "\t" << hp1.i << "\t" << *hp1.use << std::endl;
std::cout << "hp2:\t" << *hp2.ps << "\t" << hp2.i << "\t" << *hp2.use << std::endl;
swap(hp1.ps, hp2.ps); //交换指针ps
swap(hp1.i, hp2.i); //交换值i
std::cout << "now:" << std::endl;
std::cout << "hp1:\t" << *hp1.ps << "\t" << hp1.i << "\t" << *hp1.use << std::endl;
std::cout << "hp2:\t" << *hp2.ps << "\t" << hp2.i << "\t" << *hp2.use << std::endl;
std::cout << "-----------------------------------------" << std::endl;
}
std::ostream &operator<<(std::ostream &os, const HasPtr &hp)
{
os << *hp.ps << "\t" << hp.i << std::endl;
return os;
}
int main()
{
using namespace std;
vector<HasPtr> vec;
string temp;
while (cin>>temp)
{
vec.push_back(HasPtr(temp));
}
sort(vec.begin(), vec.end());
for (auto &x : vec)
cout << x << endl;
system("pause");
return 0;
}
13.32
会,能避免不必要的内存分配操作
13.33
因为需要修改数据(addMsg、remMsg),const Folder&不允许改变数据,Folder是值副本
13.34
#ifndef HEAD_H_
#define HEAD_H_
#include <string>
#include <iostream>
#include <set>
class Message
{
friend void swap(Message &lh, Message &rh);
friend class Folder;
std::string contents; //保存信息string
std::set<Folder*> folders; //保存副本所在列表set<Folder*>
void add_to_Folders(const Message &ms); <span style="white-space:pre"> </span>//把该对象的副本添加到folders对象记录的所有Folder*里
void remove_from_Folders(); //把该对象的副本从folders的所有Folder*中删除
public:
explicit Message(const std::string &str = "") :contents(str){}
Message(const Message &ms) :contents(ms.contents), folders(ms.folders)
{
add_to_Folders(ms);
}
Message &operator=(const Message &ms);
~Message()
{
remove_from_Folders();
}
void save(Folder &f); //将f插入到folders 并将该对象插入到f的sfms中
void remove(Folder &f); //将f从folders中删除 并将该对象从f的sfms中删除
void addF(Folder *f){ folders.insert(f); } <span style="white-space:pre"> </span>//把f插入到folders
void remF(Folder *f){ folders.erase(f); } <span style="white-space:pre"> </span>//从folders中删除f
};
void swap(Message &lh, Message &rh) //Message的friend
{
using std::swap;
if (&lh == &rh)
return;
for (auto f : lh.folders) //删除所有Folder对象中的lh副本
f->remMsg(&lh);
for (auto f : rh.folders)
f->remMsg(&rh);
swap(lh.contents, rh.contents);
swap(rh.folders, rh.folders);
for (auto f : lh.folders) //在所有Folder对象中添加lh副本
f->addMsg(&lh);
for (auto f : rh.folders)
f->addMsg(&rh);
}
#endif
13.35
拷贝构造函数不会把信息添加到Folder中,拷贝赋值运算符不会更新Folder,也不会将新信息添加到Folder中,析构函数没有清空保留在Folder中的数据
13.36、13.37
#ifndef HEAD_H_
#define HEAD_H_
#include <string>
#include <iostream>
#include <set>
class Message
{
friend class Folder;
friend void swap(Message &lh, Message &rh);
friend void swap(Folder &lf, Folder &rf);
std::string contents; //保存信息string
std::set<Folder*> folders; //保存副本所在列表set<Folder*>
void add_to_Folders(const Message &ms); //把该对象的副本添加到folders对象记录的所有Folder*里
void remove_from_Folders(); //把该对象的副本从folders的所有Folder*中删除
void addF(Folder *f){ folders.insert(f); } //把f插入到folders
void remF(Folder *f){ folders.erase(f); } //从folders中删除f
public:
explicit Message(const std::string &str = "") :contents(str){}
Message(const Message &ms) :contents(ms.contents), folders(ms.folders)
{
add_to_Folders(ms);
}
Message(Message &&m);//13.49
Message &operator=(Message &&m);//13.49
Message &operator=(const Message &ms);
~Message()
{
remove_from_Folders();
}
void save(Folder &f); //将f插入到folders 并将该对象插入到f的sfms中
void remove(Folder &f); //将f从folders中删除 并将该对象从f的sfms中删除
};
class Folder
{
friend void swap(Message &lh, Message &rh);
friend void swap(Folder &lf, Folder &rf);
friend class Message;
std::set<Message*> sfms; //保存信息的副本set<Message*>
void add_to_Message(Folder &f); //将该对象添加到f中的sfms保存的每个Message*的folders中
void remove_to_Message(); //将该对象从sfms中的每个Mssages*的folders中删除
public:
void addMsg(Message *ms); //添加ms到该对象
void remMsg(Message *ms); //从该对象中删除ms对象
Folder() = default;
Folder(const Folder &f) :sfms(f.sfms)
{
add_to_Message(*this);
}
Folder &operator=(Folder &f);
~Folder()
{
remove_to_Message();
}
void show();
};
#endif
#include "标头.h"
#include <iostream>
using namespace std;
void Message::save(Folder &f)
{
folders.insert(&f);
f.addMsg(this);
}
void Message::remove(Folder &f)
{
folders.erase(&f);
f.remMsg(this);
}
void Message::add_to_Folders(const Message &ms)
{
for (auto f : ms.folders)
f->addMsg(this);
}
void Message::remove_from_Folders()
{
for (auto f : folders)
f->remMsg(this);
}
Message::Message(Message &&m)
{
folders = std::move(m.folders); //使用move移动folders
for (auto f : folders)
{
f->remMsg(&m); //删除m的记录
f->addMsg(this);//添加自己
}
m.folders.clear(); //清空m
}
Message &Message::operator=(Message &&m)
{
if (this == &m)
return *this;
remove_from_Folders(); //清空自身在Folder*的记录
contents = std::move(m.contents);
folders = std::move(m.folders);
for (auto f : folders)
{
f->remMsg(&m);
f->addMsg(this);
}
m.folders.clear();
return *this;
}
Message &Message::operator=(const Message &ms)
{
if (this == &ms)
return *this;
remove_from_Folders();
contents = ms.contents;
folders = ms.folders;
add_to_Folders(ms);
return *this;
}
void Folder::addMsg(Message *ms)
{
sfms.insert(ms);
}
void Folder::remMsg(Message *ms)
{
sfms.erase(ms);
}
void Folder::add_to_Message(Folder &f)
{
for (auto m : f.sfms)
m->addF(this);
}
void Folder::remove_to_Message()
{
for (auto m : sfms)
m->remF(this);
}
Folder &Folder::operator=(Folder &f)
{
if (this == &f)
return *this;
remove_to_Message();
sfms = f.sfms;
add_to_Message(f);
return *this;
}
void Folder::show()
{
for (auto m : sfms)
cout << m->contents << "\t";
cout << endl;
}
void swap(Message &lh, Message &rh) //Message的friend
{
using std::swap;
if (&lh == &rh)
return;
for (auto f : lh.folders) //删除所有Folder对象中的lh副本
f->remMsg(&lh);
for (auto f : rh.folders)
f->remMsg(&rh);
swap(lh.contents, rh.contents);
swap(rh.folders, rh.folders);
for (auto f : lh.folders) //在所有Folder对象中添加lh副本
f->addMsg(&lh);
for (auto f : rh.folders)
f->addMsg(&rh);
}
void swap(Folder &lf, Folder &rf)
{
using std::swap;
if (&lf == &rf)
return;
for (auto m : lf.sfms)
m->remove(lf);
for (auto m : rf.sfms)
m->remove(rf);
swap(lf.sfms, rf.sfms);
for (auto m : lf.sfms)
m->save(rf);
for (auto m : rf.sfms)
m->save(lf);
}
int main()
{
Message m1("c++"), m2("primer"), m3("hello"), m4("word!");
Folder f1,f2;
f1.addMsg(&m1);
f1.addMsg(&m2);
f1.addMsg(&m3);
f2.addMsg(&m4);
Folder f3(f1);
f1.show();
cout << "---" << endl;
f2.show();
cout << "---" << endl;
f3.show();
cout << "---" << endl;
cout << "m1.remove(f1):\n";
m1.remove(f1);
f1.show();
cout << "---" << endl;
f2.show();
cout << "---" << endl;
f3.show();
cout << "---" << endl;
cout << "m2.save(f2):\n";
m2.save(f2);
f1.show();
cout << "---" << endl;
f2.show();
cout << "---" << endl;
f3.show();
cout << "---" << endl;
cout << "m4=m3:\n";
m4 = m3;
f1.show();
cout << "---" << endl;
f2.show();
cout << "---" << endl;
f3.show();
cout << "---" << endl;
cout << "f3.remMsg(m4):\n";
f3.remMsg(&m4);
f1.show();
cout << "---" << endl;
f2.show();
cout << "---" << endl;
f3.show();
cout << "---" << endl;
system("pause");
return 0;
}
13.38
拷贝并交换用在动态内存非配中会很好,但是数据成员是值时没有意义而且开支大,每次都要执行remove_from_Folders()和add_to_Folder();
13.39、13.40
#ifndef H13_39_H_
#define H13_39_H_
#include <iostream>
#include <string>
#include <memory> //allocator
#include <utility> //move
#include <initializer_list>
#include <algorithm> //for_each
class StrVec
{
std::allocator<std::string> alloc;//为所有StrVec对象分配内存用
void chk_n_alloc() //如果剩余空间为0就分配新空间
{
if (size() == capacity())
reallocate();
}
std::pair<std::string *, std::string *> alloc_n_copy(const std::string *b, const std::string *e);//创建一个内容为b到e之间的元素的对象,并返回这个对象的一对头尾指针
void free();//释放所有alloc分配的所有内存
void reallocate();//移动当前对象的元素到2倍对象大小的新对象里
std::string *elements;
std::string *first_free;
std::string *cap;
public:
StrVec() :elements(nullptr), first_free(nullptr), cap(nullptr){}
StrVec(std::initializer_list<std::string> il);
StrVec(const StrVec &s);
StrVec(StrVec &&s);//13.49
StrVec &operator=(StrVec &&s);//13.49
StrVec &operator=(const StrVec &s);
~StrVec();
void push_back(const std::string &s);//把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;
}
};
void StrVec::push_back(const std::string &s)
{
chk_n_alloc();//确保空间剩余
alloc.construct(first_free++, s);//在尾后构建一个s(s的拷贝构造函数构造),并把尾后指针first_free指向下一个
}
std::pair<std::string *, std::string *> StrVec::alloc_n_copy(const std::string *b, const std::string *e)
{
auto data = alloc.allocate(b - e);//分配并返回n个string对象的地址 string *
return{ data, std::uninitialized_copy(b, e, data) };//uninit_copy返回尾后指针string *
//把l~r之间的元素拷贝到data开始的地址,并返回data尾后,然后使用data(begin)和返回值(end)构建一个pair<string *,string *>
}
void StrVec::free()
{
if (elements)//如果不为空
{
for (auto p = first_free; p != elements;)
alloc.destroy(--p);//从最后一个元素开始向前摧毁,调用p的析构函数
//for_each(elements, first_free, [this](std::string *s){alloc.destroy(s); });//13.43
alloc.deallocate(elements, cap - first_free);//释放elements开始的n的string对象的内存
}
}
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(const StrVec &s)
{
auto newdata = alloc_n_copy(s.begin(), s.end());//创建一个s的副本 值
elements = newdata.first;//把头指向新创建的副本的头
first_free = cap = newdata.second;//把尾后和内存尾指向副本的尾(以后调用会调用chk_n_alloc,不用担心剩余空间大小)
}
StrVec::StrVec(StrVec &&s) :elements(s.elements), first_free(s.first_free), cap(s.cap)
{
s.elements = s.first_free = s.cap = nullptr;
}
StrVec &StrVec::operator=(StrVec &&s)
{
if (this == &s)
return *this;
free();
elements = s.elements;
first_free = s.first_free;
cap = s.cap;
s.elements = s.first_free = s.cap = nullptr;
return *this;
}
StrVec::~StrVec()
{
free();//清理当前对象alloc分配的内存
}
StrVec &StrVec::operator=(const StrVec &s)
{
if (this == &s)
return *this;
auto data = alloc_n_copy(s.elements, s.first_free);
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); //分配并返回newcapacity个string对象大小的空间
auto dest = newdata;
auto elem = elements;//指向当前对象的头
for (size_t i = 0; i != size(); ++i)
{
alloc.construct(dest++, std::move(*elem++));//move会让elem指向的string对象放弃自己的内存管理权并返回,然后construct使用string的移动构造函数构建dest指向的地址
} //接受dest会指向newdata的尾后
free(); //移动完后释放当前对象指向的内存
elements = newdata; //指向新头
first_free = dest; //指向新尾后
cap = elements + newcapacity; //指向内存尾
}
#endif
13.41
因为first_free是指向尾后的,如果使用前置递增,会令尾后变成未定义,把元素添加到了尾后的后一个位置
13.42
#include "../../13.39/13.39/标头.h"
#include <iostream>
#include <fstream> //ifstream
#include <string>
#include <vector>
#include <sstream> //istringstream
#include <map>
#include <set>
#include <memory> //shared_ptr
class QueryResult;
using line_no = size_t;
class TextQuery
{
std::shared_ptr<StrVec> file; //保存整个文件内容,按行分
std::map<std::string, std::shared_ptr<std::set<line_no>>> wm; //每个单词对应行号
public:
TextQuery(std::ifstream &is);
QueryResult query(const std::string &s)const; //返回QR,单词、行号set,还有关联到文件内容
};
class QueryResult
{
std::string sought;
std::shared_ptr<std::set<line_no>> lines; //记录出现的行号
std::shared_ptr<StrVec> file; //关联到文件内容
public:
friend std::ostream &print(std::ostream &os, const QueryResult &qr);
QueryResult(std::string s, std::shared_ptr<std::set<line_no>> p, std::shared_ptr<StrVec> f) :sought(s), lines(p), file(f){}
};
TextQuery::TextQuery(std::ifstream &is) :file(new StrVec()) //为智能指针file分配空间
{
std::string text;
while (getline(is, text))
{
file->push_back(text);
int n = file->size() - 1;
std::istringstream line(text);
std::string word;
while (line >> word)
{
auto &lines = wm[word]; //如果word在wm中第一次出现,那么对应的set就未分配内存,所以为空
if (!lines) //如果第一次出现
lines.reset(new std::set<line_no>());
lines->insert(n);
}
}
}
QueryResult TextQuery::query(const std::string &s)const
{
static std::shared_ptr<std::set<line_no>> nodata(new std::set<line_no>()); //当没找到单词时返回 内存常驻
auto loc = wm.find(s);
if (loc == wm.end())
return QueryResult(s, nodata, file);
else
return QueryResult(s, loc->second, file);
}
std::ostream &print(std::ostream &os, const QueryResult &qr)
{
os << qr.sought << " occurs " << qr.lines->size() << " " << (qr.lines->size() > 1 ? "times" : "time") << std::endl;
for (auto x : *qr.lines)
os << "\t(line " << x + 1 << ") " << *(qr.file->begin()+x) << std::endl; //file返回一个指向vec的智能指针,解引用后得到vector 然后使用下标运算符
return os;
}
#include "标头.h"
void runQueries(std::ifstream &infile)
{
TextQuery tq(infile);
while (1)
{
std::cout << "enter word to look for, or q to quit:";
std::string s;
if (!(std::cin >> s) || s == "q")break;
print(std::cout, tq.query(s));
}
}
int main(int argc, char **argv)
{
using namespace std;
ifstream infile(argv[1]);
if (!infile)
{
cerr << "open file error!";
exit(1);
}
runQueries(infile);
return 0;
}
13.43
见13.39
前者更易于阅读
13.44
#ifndef H13_44_H_
#define H13_44_H_
#include <memory>
class String
{
std::allocator<char> alloc;
char *elements; //头
char *first_free; //尾后
char *cap; //内存尾
void free(); //释放
void chk_n_alloc(); //检查大小并确认是否reallocate
void reallocate(); //增加内存
std::pair<char *, char *> alloc_n_copy(const char *b, const char *e); //返回创建好的副本的头和尾
public:
String() :elements(nullptr), first_free(nullptr), cap(nullptr){}
String(const String &s);
String(const char *str);
String(String &&s); //13.49
String &operator=(String &&s); //13.49
~String(){free();}
size_t size()const{return first_free-elements;} //返回已占用的大小
size_t capacity()const{return cap-elements;} //返回总大小
char *begin()const{return elements;}
char *end()const{return first_free;}
friend std::ostream &operator<<(std::ostream &os, const String &s);
String &operator=(const String &s);
String &operator=(const char *str);
};
void String::free()
{
if (elements)
{
for (auto p = first_free; p != elements;)
alloc.destroy(--p);
alloc.deallocate(elements, cap - elements);
}
}
std::pair<char *, char *> String::alloc_n_copy(const char *b, const char *e)
{
auto p = alloc.allocate(e - b);
return{ p, std::uninitialized_copy(b, e, p) };
}
void String::reallocate()
{
auto n = size() ? size() * 2 : 1;
auto c = alloc.allocate(n);
auto d = c;
auto elem = elements;
for (size_t i = 0; i != size(); ++i)
alloc.construct(d++, std::move(*elem++));
free();
elements = c;
first_free = d;
cap = elem + n;
}
void String::chk_n_alloc()
{
if (first_free == cap)
reallocate();
}
String::String(const String &s)
{
auto p = alloc_n_copy(s.begin(), s.end());
elements = p.first;
first_free = cap = p.second;
std::cout << "String(const String &)\t" << elements << std::endl; //13.48
}
String::String(String &&s) :elements(s.elements), first_free(s.first_free), cap(s.cap) //13.49
{
s.elements = s.first_free = s.cap = nullptr;
std::cout << "String(const String &&)\t" << elements << std::endl;//13.50
}
String &String::operator=(String &&s) //13.49
{
if (this == &s)
return *this;
free();
elements = s.elements;
first_free = s.first_free;
cap = s.cap;
s.elements = s.first_free = s.cap = nullptr;
std::cout << "operator= &&\t" << elements << std::endl;//13.50
return *this;
}
String::String(const char *str)
{
auto p = alloc_n_copy(str, str+strlen(str)+1);
elements = p.first;
first_free = cap = p.second;
}
String &String::operator =(const String &s)
{
if (this == &s)
return *this;
auto p = alloc_n_copy(s.begin(), s.end());
free();
elements = p.first;
first_free = cap = p.second;
std::cout << "operator =(const String &)\t" << elements << std::endl; //13.48
return *this;
}
String &String::operator =(const char *str)
{
auto p = alloc_n_copy(str, str + strlen(str) + 1);
free();
elements = p.first;
first_free = cap = p.second;
return *this;
}
std::ostream &operator<<(std::ostream &os, const String &s)
{
os << s.begin() << std::endl;
return os;
}
#endif
#include <iostream>
#include "标头.h"
#include <vector>
int main()
{
using namespace std;
vector<String> vec;
String s1("c++"), s2("primer"), s3("book"),s4("5");
vec.push_back(s1);
vec.push_back(s2);
vec.push_back(s3);
vec.push_back(std::move(s4));
system("pause");
return 0;
}
13.45
左值引用绑定到一个离开作用域才被自动销毁的对象上,右值引用绑定到一个即将要被销毁的对象上
13.46
int &&r1=f();
int &r2=vi[0];
int &r3=r1;
int &&r4=vi[0]*f();
13.47
见13.44
13.48
见13.44
13.49
见13.39、13.44、13.36
13.50
按值返回和作为初始化参数时
13.51
因为将要被销毁,智能指针离开作用域后销毁,而返回值返回后也会销魂
调用clone返回的是一个右值,所以赋值时会用移动操作而不是拷贝
13.52
调用拷贝构造rhs 把rhs与调用对象执行swap交换 返回后rhs被销毁
13.53
参数为右值,交换不必要
13.54
当使用h1=std:move(h2);时有多个运算符“=”匹配,除非拷贝赋值运算符是const &
13.55
void push_back(string &&s)
{
data->push_back(std::move(s));
}
13.56
ret是左值,当返回ret.sorted()时,调用的是 Foo Foo::sorted()const&;而不是 Foo Foo::sorted()&&;所以会进入致命的死循环和堆栈溢出
13.57
拷贝构造一个临时对象,调用sorted()&&,返回时调用移动构造函数
13.58
#include <algorithm>
#include <vector>
#include <iostream>
class Foo
{
public:
Foo sorted() && ;
Foo sorted()const&;
private:
std::vector<int> data;
};
Foo Foo::sorted() &&
{
std::cout << "&&" << std::endl;
sort(data.begin(), data.end());
return *this;
}
Foo Foo::sorted()const&
{
std::cout << "const&" << std::endl;
Foo ret(*this);
return ret.sorted(); //函数将导致运行时堆栈溢出
}
int main()
{
using namespace std;
Foo f;
f.sorted(); //无限递归
std::move(f).sorted(); //调用sorted()&&
system("pause");
return 0;
}
2015年12月13日 17:01:18 有空再看一次,隔2天全忘了