c++ primer第五版----学习笔记(十二)Ⅱ

部分习题解答:

12.1:

StrBlob的data成员是一个指向string的vector的shared_ptr,因此StrBlob的赋值不会拷贝vector的内容,而是多个StrBlob对象共享同一个vector对象。因此经过一些列操作以后,b1和b2均包含4个string。

12.2:

#include <iostream>
#include <algorithm>
#include <memory>
#include "myStrBlob.h"
using namespace std;


int main(int argc, char**argv)
{
	StrBlob b1;
	{   //新作用域
		StrBlob b2 = { "a", "an", "the" };
		b1 = b2;
		b2.push_back("about");
		cout << b2.size() << endl;
	}
	cout << b1.size() << endl;
	cout << b1.front() << " " << b1.back() << endl;
	StrBlob b3 = b1;
	cout << b3.front() << " " << b3.back() << endl;
	/*StrBlob sb;
	sb.push_back("ssss");
	sb.push_back("ssss2");
	sb.push_back("ssss3");
	sb.push_back("ssss4");
	cout << sb.back() << " " << sb.front();
	sb.pop_back();
	cout << "\n" << sb.back() << endl;
	cout << sb.empty() << endl;*/

	system("pause");
	return 0;
}
//myStrBlob.h
#ifndef MY_STRBLOB_H
#define MY_STRBLOB_H
#include <iostream>
#include <vector>
#include <string>
#include <initializer_list>
#include <memory>
using namespace std;
class StrBlob {
public:
	typedef vector<string>::size_type size_type;
	StrBlob();
	StrBlob(initializer_list<string> il);
	size_type size() const { return data->size(); }
	bool empty() const { return data->empty(); }
	//添加和删除元素
	void push_back(const string &t) { data->push_back(t); }
	void pop_back();
	//元素访问
	string& front();
	string& back();
private:
	shared_ptr<vector<string>> data;
	void check(size_type i, const string &msg) const;
};

//默认构造函数
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 StrBlob");
	return data->front();
}
//得到尾元素
string& StrBlob::back()
{
	check(0, "back on empty StrBlob");
	return data->back();
}
//将元素弹出栈
void StrBlob::pop_back()
{
	check(0, "pop_back on empty StrBlob");
	data->pop_back();
}
#endif

12.3:

不需要,push_back和pop_back会改变对象的内容,而const对象是只读的,因此不需要const版本

12.4:

因为size_type是一个无符号整数,当传递给check的参数小于0的时候,参数值会转换成一个正整数

12.5:

构造函数不是 explicit 的,意味着可以从 initializer_list 隐式转换为 StrBlob。在 StrBlob 对象中,只有一个数据成员 data,而 StrBlob 对象本身的含义,也是一个管理字符串的序列。因此,从 initializer_list 到 StrBlob 的转换,在逻辑上是可行的。而这个设计策略的缺点,可能在某些地方我们确实需要 initializer_list,而编译器仍会将之转换为 StrBlob。

12.6:

#include <iostream>
#include <algorithm>
#include <memory>
#include <vector>
#include <new>
using namespace std;

vector<int>* new_vector()
{
	return new(nothrow) vector<int>;
}
void read_vector(vector<int> *pv)
{
	int n;
	while (cin >> n)
	{
		pv->push_back(n);
	}
}
void output_vector(vector<int> *pv)
{
	for (auto w : *pv)
	{
		cout << w << " ";
	}
}
int main(int argc, char**argv)
{
	vector<int> *pv = new_vector();
	read_vector(pv);
	output_vector(pv);
	delete pv;
	pv = nullptr;
	system("pause");
	return 0;
}

12.7:

#include <iostream>
#include <algorithm>
#include <memory>
#include <vector>
#include <new>
using namespace std;

shared_ptr<vector<int>> new_vector()
{
	return make_shared<vector<int>>();
}
void read_vector(shared_ptr<vector<int>> pv)
{
	int n;
	while (cin >> n)
	{
		pv->push_back(n);
	}
}
void output_vector(shared_ptr<vector<int>> pv)
{
	for (auto &w : *pv)
	{
		cout << w << " ";
	}
	cout << endl;
}
int main(int argc, char**argv)
{
	auto pv = new_vector();
	read_vector(pv);
	output_vector(pv);
	system("pause");
	return 0;
}

12.8:
该程序通过new返回的指针值来区分内存分配成功或失败——成功返回一个合法指针,转换为整型是一个非零值,可转换为bool值true;分配失败,p得到nullptr,其整型值是0,可转换为bool值false. 
但普通new调用在分配失败时抛出一个异常bad_alloc,而不是返回nullptr,因此程序不能达到预想目的。
可将new int改为new (nothrow) int 来令new在分配失败时不抛出异常,而是返回nullptr。但这仍然不是一个好方法,应该通过捕获异常或是判断返回的指针来判断true或false,而不是依赖类型转换。
12.9:

q,r为内置类型指针,保存动态内存的地址,进行二次赋值之后,r原来指向的内存空间将得不到释放,造成内存泄漏

q2,r2为智能指针,r2进行赋值之后,其计数器将减一,由于r2是指向该内存空间的唯一智能指针,所以该内存会得到释放

12.10:

此调用是正确的,利用p创建一个临时的shared_ptr赋予了process的参数ptr,p和ptr都指向相同的int对象,引用计数被正确地置为2。process执行完毕后,ptr被销毁,引用计数减1,这是正确的——只有p指向它。

12.11:

此调用是错误的。p.get()获得一个普通指针,指向p所共享的int对象。利用此指针创建一个shared_ptr,而不是利用p创建一个shared_ptr,将不会形成正确的动态对象共享。编译器会认为p和ptr是使用两个地址(虽然他们相等)创建的两个不相干的shared_ptr,而非共享同一个动态对象。这样,两者的引用计数均为1。当process执行完毕后,ptr的引用计数减为0,所管理的内存地址被释放,而此内存就是p所管理的。p成为一个管理空悬指针的shared_ptr。

12.12:

(a)合法                        (b)不合法,参数必须是智能指针类型,不能用构造函数隐式转换

(c)不合法,同上         (d)合法,处理完内存被释放

12.13:

删除p之后,导致p指向的内存被释放,此时sp就会变成空悬指针,在sp指针被销毁时,该块内存会被二次delete

12.14、12.15:

#include <iostream>
#include <string>
#include <memory>
using namespace std;

//表示我们正在连接什么
struct  destination{
	string ip;
	int port;
	destination(string i,int p):ip(i),port(p){}
};   
struct  connection{
	string ip;
	int port;
	connection(string i,int p):ip(i),port(p){}
};      //使用连接所需的信息
//打开连接
connection connect(destination* pv) 
{
	shared_ptr<connection> sp(new connection(pv->ip, pv->port));
	cout << "start create connection to " << pv->ip << ":" << pv->port << endl;
	return *sp;
}
//关闭给定的连接
void disconnect(connection c)
{
	cout << "you have disconnect to " << c.ip << ":" << c.port << endl;
}
//函数相当于delete操作
void end_connection(connection *p)
{
	disconnect(*p);
}

//使用shared_ptr来管理一个connection
void f(destination &d)
{
	connection c = connect(&d);
	shared_ptr<connection> p(&c, end_connection);
	//12.15   shared_ptr<connection> p(&c, [](connection *p) {disconnect(*p); });
	cout << "you have connect to " << d.ip << ":" << d.port << endl;
}
int main(int argc,char *argv[])
{
	destination pv("192.168.1.5", 3430);
	f(pv);
	system("pause");
    return 0;
}

12.18:

unique_ptr独占对象的所有权,不能拷贝和赋值。release操作是用来将对象的所有权转移给另一个unique_ptr的。
而多个shared_ptr可以共享对象的所有权。需要共享时,可以简单拷贝和赋值。因此,并不需要release这样的操作来转移所有权。

12.19:

//myStrBlob.h
#ifndef MY_STRBLOB_H
#define MY_STRBLOB_H
#include <iostream>
#include <vector>
#include <string>
#include <initializer_list>
#include <memory>
using namespace std;
class StrBlobPtr;

class StrBlob {
	friend class StrBlobPtr;
public:
	typedef vector<string>::size_type size_type;
	StrBlob();
	StrBlob(initializer_list<string> il);
	size_type size() const { return data->size(); }
	bool empty() const { return data->empty(); }
	//添加和删除元素
	void push_back(const string &t) { data->push_back(t); }
	void pop_back();
	//元素访问
	string& front();
	string& back();

	StrBlobPtr begin();
	StrBlobPtr end();
private:
	shared_ptr<vector<string>> data;
	void check(size_type i, const string &msg) const;
};

//默认构造函数
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 StrBlob");
	return data->front();
}
//得到尾元素
string& StrBlob::back()
{
	check(0, "back on empty StrBlob");
	return data->back();
}
//将元素弹出栈
void StrBlob::pop_back()
{
	check(0, "pop_back on empty StrBlob");
	data->pop_back();
}


class StrBlobPtr {
public:
	StrBlobPtr() : curr(0) { }
	StrBlobPtr(StrBlob &a, size_t sz = 0) : wptr(a.data), curr(sz) { }
	string& deref() const;
	StrBlobPtr& incr();      //前缀递增
private:
	// 若检查成功,check返回一个指向vector的shared_ptr
	shared_ptr<vector<string>> check(size_t, const string&) const;
	// 保存一个weak_ptr,意味着底层vector可能会被销毁
	weak_ptr<vector<string>> wptr;
	size_t curr;
};

inline shared_ptr<vector<string>> StrBlobPtr::check(size_t i, const string &msg) const
{
	auto ret = wptr.lock();    //vector还存在吗?
	if (!ret)
		throw runtime_error("unbound StrBlobPtr");
	if (i >= ret->size())
		throw out_of_range(msg);
	return ret;               //否则,返回指向vector的shared_ptr
}

inline string& StrBlobPtr::deref() const
{
	auto p = check(curr, "dereference past end");
	return (*p)[curr];     //(*p)是对象所指的vector
}

// 前缀递增:返回递增后的对象的引用
inline StrBlobPtr& StrBlobPtr::incr()
{
	// 如果curr已经指向容器的尾后位置,就不递增它
	check(curr, "increment psat end of StrBlobPtr");
	++curr;             //推进当前位置
	return *this;
}

StrBlobPtr StrBlob::begin() { return StrBlobPtr(*this); }
StrBlobPtr StrBlob::end() { return StrBlobPtr(*this, data->size()); }
#endif

12.20:

#include <iostream>
#include <fstream>
#include "my_StrBlob.h"
using namespace std;

int main(int argc, char **argv)
{

	ifstream in(argv[1]);
	if (!in) {
		cout<<"Open input file failed"<<endl;
		return -1;
	}
        StrBlob b;
	string s;
	while (getline(in, s))
		b.push_back(s);
	for (auto it = b.begin(); neq(it, b.end()); it.incr())
		cout<<it.deref()<<endl; 
        syatem("pause");
	return 0;
}

12.21:

原版本更好,将合法性检查语句与元素获取的返回语句分离开来,代码更清晰

12.23:

#include <iostream> 
#include <cstring>
#include <string>
using namespace std;

/*char* connect(const char *a, const char *b)
{
	auto p = new char[strlen(a) + strlen(b)];
	int i = 0;
	for (; i < strlen(a); ++i)
	{
		p[i] = a[i];
	}
	for (int j = 0; j < strlen(b); ++j)
	{
		p[i + j] = b[j];
	}
	return p;
}*/
string connect(string a, string b)
{
	return a + b;
}
int main(int argc,char *argv[])
{
	auto p = connect("hello", "world");
	/*for (int i = 0; i < strlen(p);++i)
	{
		cout << p[i] << " ";
	}
	delete[] p;*/
	cout << p;
	system("pause");
	return 0; 
} 

12.24:

char*  input()
{
	int i = 0, size = 10;
	char c;
	auto p = new char[10];
	while (cin >> c)
	{
		p[i] = c;
		++i;
		if (i >= size)     //如果输入的字符大于原来的字符长度,则将长度重新分配
		{
			size *= 2;
			auto tmp = new char[size];    //重新分配内存
			for (int j = 0; j < size; ++j)
			{
				tmp[j] = p[j];
			}
			delete[] p;    //将原来分配的内存删除,将p指向新分配的内存
			p = tmp;
		}
	}
	p[i] = '\0';
	return p;
}
int main(int argc,char *argv[])
{
	auto p = input();
	cout << p << endl;
	system("pause");
	return 0; 
} 

12.26:

#include <iostream> 
#include <cstring>
#include <string>
#include <memory>
using namespace std;
#define n 120 

int main(int argc,char *argv[])
{
	allocator<string> alloc;
	auto const p = alloc.allocate(n);
	string s;
	auto q = p;
	while (cin >> s && q != p + n)
	{
		alloc.construct(q++, s);
	}
	const size_t size = q - p;
	for (auto i = 0; i < size; ++i)
	{
		cout << p[i]<< " ";
	}
	while (q != p)
	{
		alloc.destroy(--q);
	}
	alloc.deallocate(p, size);
	system("pause");
	return 0; 
} 

12.27:

#ifndef TEXTQUERY_H
#define TEXTQUERY_H
#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <fstream>
#include <sstream>
#include "QueryResult.h"
using namespace std;

class QueryResult;
class TextQuery {
public:
	TextQuery(ifstream& input);
	QueryResult query(const string s);
private:
	vector<string>* text;
	map<string, set<int>> mp;
};

TextQuery::TextQuery(ifstream& input)
{
	text = new vector<string>();
	string s;
	string word;
	int line = 0;
	while (getline(input, s))
	{
		text->push_back(s);
		istringstream in(s);
		while (in >> word)
		{
			mp[word].insert(line);
		}
		++line;
	}
}
QueryResult TextQuery::query(const string s)
{
	return QueryResult(*this, s);
}
#endif
#ifndef QUERYRESULT_H
#define QUERYRESULT_H
#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <fstream>
#include <sstream>
#include "TextQuery.h"
using namespace std;
class QueryResult {
	friend ostream& print(ostream& os, QueryResult& p);
public:
	QueryResult(TextQuery& t, string& s) {
		l = t.lines[s];
		text = t.text;
	};

private:
	set<int> st;            //出现的行号
	vector<string>* text;   //输入文件
};
ostream& print(ostream& os, QueryResult& q)
{
	if (q.st.size() == 0)
		os << "word not found" << endl;
	else
		for (auto i : q.st)
			cout << "(line " << i << ") " << (*q.text)[i] << endl;
	return os;

}
#endif // !QUERYRESULT_H

12.28:

//功能不完善,有漏洞
#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <fstream>
#include <sstream>

using namespace std;

int main(int argc,char *argv[])
{
	vector<string> text;
	map<string, set<int>> mp;
	ifstream infile("Data.txt");
	string s;
	int line = 0;
	while (infile >> s)
	{
		text.push_back(s);
		string tmp;
		istringstream im(s);
		while (im >> tmp)
		{
			mp[tmp].insert(line);
		}
		++line;
	}
	while (true)
	{
		cout << "enter word to look for, or q to quit: ";
		string s;
		if (!(cin >> s) || s == "q") break;
		auto ret = mp[s];
		if (ret.size() == 0)
		{
			cout << "word " << s << " not found!" << endl;
		}
		else
		{
			for (auto w : ret)
			{
				cout << "(line " << w << ")" << text[w] << endl;  //单词出现在第几位
			}
		}
	}
	system("pause");
	return 0; 
} 

12.31:

用set,自动去重排序

12.30、12.31、12.32:

#ifndef TEXTQUERY_H
#define TEXTQUERY_H
#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <fstream>
#include <sstream>
#include "myStrBlob.h"
#include "QueryResult.h"
using namespace std;

class QueryResult;

class TextQuery {
public:
	using line_no = StrBlob::size_type;
	TextQuery(ifstream&);                          //读取文本,建立联系
	QueryResult query(const string&) const;
private:
	shared_ptr<StrBlob> file;                 //输入文件
	map<string, shared_ptr<set<line_no>>> wm;        //单词与行号关联的map
};

TextQuery::TextQuery(ifstream& is) : file(new StrBlob)
{
	string text;
	while (getline(is, text))          //文件中的每一行,按行读取
	{
		file->push_back(text);          //保存该行文本
		int n = file->size() - 1;       //当前文本行号
		istringstream line(text);      //对于行中的每一个单词
		string word;
		while (line >> word)
		{
			auto &lines = wm[word];    //得到一个shared_ptr指针
			if (!lines)                //如果该指针为空,则分配一个新的set
				lines.reset(new set<line_no>);
			lines->insert(n);           //将行号插入set中
		}
	}
}
QueryResult TextQuery::query(const string &s) const
{
	//如果未找到给定单词,则返回一个指针
	static shared_ptr<set<line_no>> nodata(new set<line_no>);
	//使用find查找,避免将单词插入到wm中
	auto loc = wm.find(s);
	if (loc == wm.end())    
	{
		return QueryResult(s, nodata, file);
	}
	else
		return QueryResult(s, loc->second, file);
}
#endif
#ifndef QUERYRESULT_H
#define QUERYRESULT_H
#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <fstream>
#include <sstream>
#include "myStrBlob.h"
using namespace std;
string make_plural(size_t ctr, const string &word, const string &ending)
{
	return (ctr > 1) ? word + ending : word;
}
class StrBlob;
class QueryResult {
	friend ostream& print(ostream&,const QueryResult&);
public:
	using line_no =  vector<string>::size_type;
	QueryResult(string s, shared_ptr<set<line_no>> p, shared_ptr<StrBlob> f)
		:sought(s), lines(p), file(f) {}
	set<line_no>::iterator begin() const {           //12.33
		return lines->begin();
	}
	set<line_no>::iterator end() const {              //12.33
		return lines->end();
	}
	shared_ptr<StrBlob> get_file() const {        //12.33
		return file;
	}

	string sought;   //查询的单词
	shared_ptr<set<line_no>> lines;            //出现的行号
	shared_ptr<StrBlob> file;   //输入文件
};
ostream& print(ostream& os,const QueryResult& qr)
{
	os << qr.sought << " occurs " << qr.lines->size() << " " << make_plural(qr.lines->size(), "time", "s") << endl;
	for (auto num : *qr.lines)
	{
		os << "\t(line " << num + 1 << ")" << qr.file->begin().deref(num) << endl;  //调用重载的deref输出保存的语句
	}
	return os;
}

#endif // !QUERYRESULT_H
#ifndef MY_STRBLOB_H
#define MY_STRBLOB_H
#include <iostream>
#include <vector>
#include <string>
#include <initializer_list>
#include <memory>
using namespace std;
class StrBlobPtr;

class StrBlob {
	friend class StrBlobPtr;
public:
	typedef vector<string>::size_type size_type;
	StrBlob();
	StrBlob(initializer_list<string> il);
	size_type size() const { return data->size(); }
	bool empty() const { return data->empty(); }
	//添加和删除元素
	void push_back(const string &t) { data->push_back(t); }
	void pop_back();
	//元素访问
	string& front();
	string& back();

	StrBlobPtr begin();
	StrBlobPtr end();
private:
	shared_ptr<vector<string>> data;
	void check(size_type i, const string &msg) const;
};

//默认构造函数
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 StrBlob");
	return data->front();
}
//得到尾元素
string& StrBlob::back()
{
	check(0, "back on empty StrBlob");
	return data->back();
}
//将元素弹出栈
void StrBlob::pop_back()
{
	check(0, "pop_back on empty StrBlob");
	data->pop_back();
}


class StrBlobPtr {
public:
	StrBlobPtr() : curr(0) { }
	StrBlobPtr(StrBlob &a, size_t sz = 0) : wptr(a.data), curr(sz) { }
	string& deref() const;
	string& deref(int off) const;
	StrBlobPtr& incr();      //前缀递增
private:
	// 若检查成功,check返回一个指向vector的shared_ptr
	shared_ptr<vector<string>> check(size_t, const string&) const;
	// 保存一个weak_ptr,意味着底层vector可能会被销毁
	weak_ptr<vector<string>> wptr;
	size_t curr;
};

inline shared_ptr<vector<string>> StrBlobPtr::check(size_t i, const string &msg) const
{
	auto ret = wptr.lock();    //vector还存在吗?
	if (!ret)
		throw runtime_error("unbound StrBlobPtr");
	if (i >= ret->size())
		throw out_of_range(msg);
	return ret;               //否则,返回指向vector的shared_ptr
}

inline string& StrBlobPtr::deref() const
{
	auto p = check(curr, "dereference past end");
	return (*p)[curr];     //(*p)是对象所指的vector
}


inline string& StrBlobPtr::deref(int off) const

{

	auto p = check(curr + off, "dereference past end");

	return (*p)[curr + off];	//(*p)是对象所指的vector

}

// 前缀递增:返回递增后的对象的引用
inline StrBlobPtr& StrBlobPtr::incr()
{
	// 如果curr已经指向容器的尾后位置,就不递增它
	check(curr, "increment psat end of StrBlobPtr");
	++curr;             //推进当前位置
	return *this;
}

StrBlobPtr StrBlob::begin() { return StrBlobPtr(*this); }
StrBlobPtr StrBlob::end() { return StrBlobPtr(*this, data->size()); }
#endif
#include<iostream>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<sstream>
#include<fstream>
#include<memory>
#include<stdexcept>
#include "TextQuery.h"
using namespace std;

void runQueries(ifstream &infile)
{
	TextQuery tq(infile);
	while (true) {
		cout << "enter word to look for, or q to quit: ";
		string s;
		if (!(cin >> s) || s == "q") break;
		print(cout, tq.query(s)) << endl;
	}
}

int main(int argc, char *argv[])
{
	ifstream infile("Data.txt");
	runQueries(infile);
	system("pause");
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_38790716/article/details/82709645