c++primer第五版第十三章练习

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天全忘了





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值