C++ Prime 第十二章 动态内存

2023-05-05~2023-05-07

12.1.1节练习

alt

练习12.1:

b1:4个元素,b2:4个元素

练习12.2:

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

class StrBlob
{
public:
	StrBlob() : data(make_shared<vector<string>>()) {};
	StrBlob(initializer_list<string> il) : data(make_shared<vector<string>>(il)) {};
	vector<string>::size_type size() const
	{
		return data->size();
	}
	bool empty() const { return data->empty(); };
	void push_back(const string& s)
	{
		data->push_back(s);
	}
	string& front()
	{
		check(0, "front on empty StrBlob");
		return data->front();
	}
	string& back()
	{
		check(0, "back on empty StrBlo");
		return data->back();
	}
	void pop_back()
	{
		check(0, "pop_back on empty StrBlo");
		data->pop_back();
	}
	string& const front() const
	{
		check(0, "const front on empty StrBlob");
		return data->front();
	}
	string& const back() const
	{
		check(0, "const back on empty StrBlob");
		return data->back();
	}

private:
	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);
		}
	}
};

练习12.3:

不需要,const对象不应该被修改

练习12.4:

check函数是一个私有函数,提供给类内部其他函数操作数据时的一个前置检查,应该由其他函数通过参数的形式来判断,而不是在check函数内部进行限制

练习12.5:

12.1.2节练习:

alt

练习12.6:

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

vector<int>* get_vec_ptr()
{
	vector<int>* vecPtr = new vector<int>();
	return vecPtr;
}

void push_vec(vector<int>* ptr)
{
	int temp;
	while (cin >> temp)
	{
		ptr->push_back(temp);
	}
}

void print_vec(vector<int>* ptr)
{
	for (size_t i = 0; i < (*ptr).size(); ++i)
	{
		cout << (*ptr)[i] << endl;
	}
}

int main()
{
	auto ptr = get_vec_ptr();
	push_vec(ptr);
	print_vec(ptr);
	delete ptr;
	ptr = nullptr;
	system("pause");
	return 0;
}

练习12.7:

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

shared_ptr<vector<int>> get_vec_ptr()
{
	shared_ptr<vector<int>> ptr(new vector<int>());
	return ptr;
}

void push_vec(shared_ptr<vector<int>> ptr)
{
	int temp;
	while (cin >> temp)
	{
		(*ptr).push_back(temp);
	}
}

void print_vec(shared_ptr<vector<int>> ptr)
{
	for (size_t i = 0; i < (*ptr).size(); ++i)
	{
		cout << (*ptr)[i] << endl;
	}
}

int main()
{
	auto ptr = get_vec_ptr();
	push_vec(ptr);
	print_vec(ptr);
	system("pause");
	return 0;
}

练习12.8:

错误,函数返回值类型是bool但是实际上返回的是一个int类型的指针

练习12.9:

r指针指向的内存空间还没释放就将r指针重新指向q指针指向的内存空间,存在内存泄露问题
智能指针r2指向q2时,由于r2原本指向的内存空间的引用计数=0,该内存空间被释放,智能指针q2的引用计数+1

12.1.3节练习

alt

练习12.10:

代码可以正常执行,但是使用process(p)方式可以减小性能开销,不需要额外创建一个临时变量,创建、销毁临时变量都会影响开销

练习12.11:

会导致指针指针p被释放两次引起程序异常

练习12.12:

(a)合法,将智能指针sp通过值传递的方式传递给函数process
(b)、(c)不合法,无法通过隐式转化将new分配的指针转化成指针指针
(d)合法,创建一个临时变量,将临时变量传递给函数process

练习12.13:

程序结束时会自动释放智能指针sp指向的内存空间,但是该内存空间已经被指针p释放过了,重复释放会导致程序异常

12.1.4节练习

alt

练习12.14:

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

struct destination {};
struct connection
{
	connection(destination&) {};
};
connection connect(destination& d)
{
	cout << "连接" << endl;
	return connection(d);
};
void disconnect(connection* c)
{
	cout << "关闭" << endl;
};
void end_connect(connection* c) { disconnect(c); };
void f(destination& d)
{
	connection c = connect(d);
	shared_ptr<connection> cptr(&c, end_connect);
}


int main()
{
	destination info;
	f(info);
	system("pause");
	return 0;
}

练习12.15:

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

struct destination {};
struct connection
{
	connection(destination&) {};
};
connection connect(destination& d)
{
	cout << "连接" << endl;
	return connection(d);
};
void disconnect(connection* c)
{
	cout << "关闭" << endl;
};
void f(destination& d)
{
	connection c = connect(d);
	shared_ptr<connection> cptr(&c, [](connection* p) {disconnect(p); });
}


int main()
{
	destination info;
	f(info);
	system("pause");
	return 0;
}

12.1.5节练习

练习12.16:

练习12.17:

(a)错误,不能将一个int类型的数据赋值给unique_ptr< int > 类型
(b)、(d)错误,将智能指针指向非动态内存的指针
(c)、(e)合法
(f)对同一内存空间重复释放,导致程序异常

练习12.18:

release用来放弃并转让对内存空间的所有权,shared_ptr类型的指针可以通过赋值、拷贝的方式进行所有权的放弃、转让

12.1.6节练习

alt

练习12.19:

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

class StrBlob
{
	friend class StrBlobPtr;
public:
	StrBlob() : data(make_shared<vector<string>>()) {};
	StrBlob(initializer_list<string> il) : data(make_shared<vector<string>>(il)) {};
	vector<string>::size_type size() const
	{
		return data->size();
	}
	bool empty() const { return data->empty(); };
	void push_back(const string& s)
	{
		data->push_back(s);
	}
	string& front()
	{
		check(0, "front on empty StrBlob");
		return data->front();
	}
	string& back()
	{
		check(0, "back on empty StrBlo");
		return data->back();
	}
	void pop_back()
	{
		check(0, "pop_back on empty StrBlo");
		data->pop_back();
	}
	string& const front() const
	{
		check(0, "const front on empty StrBlob");
		return data->front();
	}
	string& const back() const
	{
		check(0, "const back on empty StrBlob");
		return data->back();
	}
	StrBlobPtr begin();
	StrBlobPtr end();

private:
	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);
		}
	}
};

class StrBlobPtr
{
public:
	StrBlobPtr() : curr(0) {};
	StrBlobPtr(StrBlob& s, size_t sz = 0) : wptr(s.data), curr(sz) {};
	string& deref() const
	{
		auto ret = check(curr, "increment past end of StrBlobPtr");
		return (*ret)[curr];
	}
	StrBlobPtr& incr()
	{
		auto ret = check(curr, "increment past end of StrBlobPtr");
		++curr;
		return *this;
	}
	StrBlobPtr& redu()
	{
		auto ret = check(curr-1, "increment past end of StrBlobPtr");
		--curr;
		return *this;
	}


private:
	size_t curr;
	weak_ptr<vector<string>> wptr;
	shared_ptr<vector<string>> check(size_t i, const string& msg) const
	{
		auto ret = wptr.lock();
		if (!ret)
		{
			throw runtime_error("wptr unbound");
		}
		if (i > ret->size())
		{
			throw out_of_range(msg);
		}
		return ret;
	}
};

StrBlobPtr StrBlob::begin()

{
	return StrBlobPtr(*this);
}

StrBlobPtr StrBlob::end()
{
	auto ret = StrBlobPtr(*this, data->size());
	return ret;
}


int main()
{
	StrBlob s1 = { "1", "2", "3" };
	StrBlobPtr sptr1 = s1.begin();
	cout << sptr1.deref() << endl;
	StrBlobPtr sptr2 = s1.end();
	sptr2.redu();
	cout << sptr2.deref() << endl;
	system("pause");
	return 0;
}

练习12.20:

#include<iostream>
#include<vector>
#include<memory>
#include<fstream>
#include<sstream>
using namespace std;

class StrBlob
{
	friend class StrBlobPtr;
public:
	StrBlob() : data(make_shared<vector<string>>()) {};
	StrBlob(initializer_list<string> il) : data(make_shared<vector<string>>(il)) {};
	vector<string>::size_type size() const
	{
		return data->size();
	}
	bool empty() const { return data->empty(); };
	void push_back(const string& s)
	{
		data->push_back(s);
	}
	string& front()
	{
		check(0, "front on empty StrBlob");
		return data->front();
	}
	string& back()
	{
		check(0, "back on empty StrBlo");
		return data->back();
	}
	void pop_back()
	{
		check(0, "pop_back on empty StrBlo");
		data->pop_back();
	}
	string& const front() const
	{
		check(0, "const front on empty StrBlob");
		return data->front();
	}
	string& const back() const
	{
		check(0, "const back on empty StrBlob");
		return data->back();
	}
	StrBlobPtr begin();
	StrBlobPtr end();

private:
	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);
		}
	}
};

class StrBlobPtr
{
public:
	StrBlobPtr() : curr(0) {};
	StrBlobPtr(StrBlob& s, size_t sz = 0) : wptr(s.data), curr(sz) {};
	string& deref() const
	{
		auto ret = check(curr, "increment past end of StrBlobPtr");
		return (*ret)[curr];
	}
	StrBlobPtr& incr()
	{
		auto ret = check(curr, "increment past end of StrBlobPtr");
		++curr;
		return *this;
	}
	StrBlobPtr& redu()
	{
		auto ret = check(curr-1, "increment past end of StrBlobPtr");
		--curr;
		return *this;
	}


private:
	size_t curr;
	weak_ptr<vector<string>> wptr;
	shared_ptr<vector<string>> check(size_t i, const string& msg) const
	{
		auto ret = wptr.lock();
		if (!ret)
		{
			throw runtime_error("wptr unbound");
		}
		if (i > ret->size())
		{
			throw out_of_range(msg);
		}
		return ret;
	}
};

StrBlobPtr StrBlob::begin()

{
	return StrBlobPtr(*this);
}

StrBlobPtr StrBlob::end()
{
	auto ret = StrBlobPtr(*this, data->size());
	return ret;
}


int main()
{
	StrBlob s1;
	ifstream fs("data.txt");
	string line;
	int times = 0;
	while (getline(fs, line))
	{
		string word;
		istringstream ss(line);
		while (ss >> word)
		{
			s1.push_back(word);
			++times;
		}
	}


	StrBlobPtr sptr1 = s1.begin();
	while (times>0)
	{
		cout << sptr1.deref() << endl;
		sptr1.incr();
		--times;
	}
	system("pause");
	return 0;
}

练习12.21:

练习12.22:

增加const类型的构造函数、cbegin、cend

#include<iostream>
#include<vector>
#include<memory>
#include<fstream>
#include<sstream>
using namespace std;

class StrBlob
{
	friend class StrBlobPtr;
public:
	StrBlob() : data(make_shared<vector<string>>()) {};
	StrBlob(initializer_list<string> il) : data(make_shared<vector<string>>(il)) {};
	vector<string>::size_type size() const
	{
		return data->size();
	}
	bool empty() const { return data->empty(); };
	void push_back(const string& s)
	{
		data->push_back(s);
	}
	string& front()
	{
		check(0, "front on empty StrBlob");
		return data->front();
	}
	string& back()
	{
		check(0, "back on empty StrBlo");
		return data->back();
	}
	void pop_back()
	{
		check(0, "pop_back on empty StrBlo");
		data->pop_back();
	}
	string& const front() const
	{
		check(0, "const front on empty StrBlob");
		return data->front();
	}
	string& const back() const
	{
		check(0, "const back on empty StrBlob");
		return data->back();
	}
	StrBlobPtr begin();
	StrBlobPtr end();
	StrBlobPtr cbegin() const;
	StrBlobPtr cend() const;

private:
	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);
		}
	}
};

class StrBlobPtr
{
public:
	StrBlobPtr() : curr(0) {};
	StrBlobPtr(StrBlob& s, size_t sz = 0) : wptr(s.data), curr(sz) {};
	StrBlobPtr(const StrBlob& s, size_t sz = 0) : wptr(s.data), curr(sz) {};
	string& deref() const
	{
		auto ret = check(curr, "increment past end of StrBlobPtr");
		return (*ret)[curr];
	}
	StrBlobPtr& incr()
	{
		auto ret = check(curr, "increment past end of StrBlobPtr");
		++curr;
		return *this;
	}
	StrBlobPtr& redu()
	{
		auto ret = check(curr-1, "increment past end of StrBlobPtr");
		--curr;
		return *this;
	}


private:
	size_t curr;
	weak_ptr<vector<string>> wptr;
	shared_ptr<vector<string>> check(size_t i, const string& msg) const
	{
		auto ret = wptr.lock();
		if (!ret)
		{
			throw runtime_error("wptr unbound");
		}
		if (i > ret->size())
		{
			throw out_of_range(msg);
		}
		return ret;
	}
};

StrBlobPtr StrBlob::begin()

{
	return StrBlobPtr(*this);
}

StrBlobPtr StrBlob::end()
{
	auto ret = StrBlobPtr(*this, data->size());
	return ret;
}

StrBlobPtr StrBlob::cbegin() const

{
	return StrBlobPtr(*this);
}

StrBlobPtr StrBlob::cend() const
{
	auto ret = StrBlobPtr(*this, data->size());
	return ret;
}


int main()
{
	const StrBlob s1 = {"100", "200", "300"};
	int times = s1.size();
	StrBlobPtr sptr1 = s1.cbegin();
	while (times > 0)
	{
		cout << sptr1.deref() << endl;
		sptr1.incr();
		--times;
	}
	system("pause");
	return 0;
}

12.2.1节练习

alt

练习12.23:

#include<iostream>
#include<vector>
#include<memory>
#include<fstream>
#include<sstream>
using namespace std;


int main()
{
	char const* str1 = "abc";
	char const* str2 = "def";
	string s = string(str1) + str2;
	char* p = new char[s.size()+1];
	strcpy_s(p, s.size()+1, s.c_str());
	for (int i = 0; i < s.size(); ++i)
	{
		cout << p[i] << endl;
	}

	string s1 = "abc";
	string s2 = "bcd";
	string s3 = s1 + s2;
	char* p2 = new char[s3.size() + 1];
	strcpy_s(p2, s3.size() + 1, s3.c_str());
	for (int i = 0; i < s3.size(); ++i)
	{
		cout << p2[i] << endl;
	}
	system("pause");
	return 0;
}

练习12.24:

#include<iostream>
#include<vector>
#include<memory>
#include<fstream>
#include<sstream>
using namespace std;


int main()
{
	char temp;
	char* p = new char[20];
	int index = 0;
	while (cin >> temp)
	{
		p[index++] = temp;
	}
	for (int i = 0; i < index; ++i)
	{
		cout << p[i] << endl;
	}
	delete[]p;
	system("pause");
	return 0;
}

练习12.25:

delete[] pa;

12.2.2节练习

alt

练习12.26:

#include<iostream>
#include<vector>
#include<memory>
#include<fstream>
#include<sstream>
using namespace std;


int main()
{
	int size = 20;
	allocator<string> alloc;
	auto const p = alloc.allocate(size);
	auto q = p;
	string temp;
	while (cin >> temp && q != p + size)
	{
		alloc.construct(q++, temp);
	}
	while (q != p)
	{
		cout << *(--q) << endl;
		alloc.destroy(q);
	}
	alloc.deallocate(p, size);
	system("pause");
	return 0;
}

12.3.1节练习

alt

练习12.27:

#include<iostream>
#include<vector>
#include<memory>
#include<fstream>
#include<sstream>
#include<set>
#include<map>
using namespace std;

class QueryResult;
class TextQuery
{
public:
	using line_no_type = vector<string>::size_type;
	TextQuery(ifstream& infile)
	{
		// 创建vector<string>容器并使用智能指针管理
		lines_vec = make_shared<vector<string>>();
		string line;
		string word;
		int line_no = 0;
		while (getline(infile, line))
		{
			// 分行保存到vector中
			lines_vec->push_back(line);
			istringstream ss(line);
			while (ss >> word)
			{
				// 在单词与行号(set)的map映射中查找单词是否存在
				// 如果存在,在该行号(set)中插入当前行
				// 如果不存在,将这个行号(set)指针指向新创建的set
				auto &line_no_set = this->word_lineno_map[word];
				if (!line_no_set)
				{
					line_no_set.reset(new set<line_no_type>);
				}
				// set容器自带去重、排序
				line_no_set->insert(line_no);
			}
			++line_no;
		}
	}
	QueryResult query(const string& s);
private:
	shared_ptr<vector<string>> lines_vec;
	map<string, shared_ptr<set<line_no_type>>> word_lineno_map;
};

class QueryResult
{
	using line_no_type = TextQuery::line_no_type;
	friend ostream& print(ostream& out, const QueryResult& qr);
public:
	QueryResult() = default;
	QueryResult(const string& s, shared_ptr<vector<string>> l, shared_ptr<set<line_no_type>> l_no) :
	word(s), lines(l), lines_no(l_no){};
private:
	shared_ptr<vector<string>> lines;
	shared_ptr<set<line_no_type>> lines_no;
	const string word;
};

QueryResult TextQuery::query(const string& s)
{
	auto ret = this->word_lineno_map.find(s);
	if (ret != this->word_lineno_map.end())
	{
		return QueryResult(s, this->lines_vec, ret->second);
	};
	return QueryResult();
};

ostream& print(ostream& out, const QueryResult& qr)
{
	if (qr.word == "")
	{
		out << "not found word" << endl;
		return out;
	}
	out << qr.word << " occurs " << qr.lines_no->size() << " times " << endl;

	for (auto line_no : *qr.lines_no)
	{
		cout << "\t" << "(line " << line_no << ")" << (*qr.lines)[line_no] << endl;
	}
	return out;
};

void runQueries(ifstream& infile)
{
	TextQuery tq(infile);
	string word;
	while (cin >> word)
	{
		print(cout, tq.query(word));
	}
}


int main()
{
	ifstream infile("test_word.txt");
	runQueries(infile);

	system("pause");
	return 0;
}

练习12.28:

#include<iostream>
#include<vector>
#include<memory>
#include<fstream>
#include<sstream>
#include<set>
#include<map>
using namespace std;


void get_txt_info(ifstream& infile, vector<string>&v, map<string, set<string::size_type>>&m)
{
	string line;
	string word;
	string::size_type line_no = 0;
	while (getline(infile, line))
	{
		v.push_back(line);
		istringstream ss(line);
		while (ss >> word)
		{
			m[word].insert(line_no);
		}
		++line_no;
	}
}


void runQueries(ifstream& infile)
{
	vector<string>lines;
	map<string, set<string::size_type>> words_map;
	get_txt_info(infile, lines, words_map);
	string word;
	while (cin >> word)
	{
		auto ret = words_map.find(word);
		if (ret != words_map.end())
		{
			cout << word << " occurs " << words_map[word].size()+1 << " times " << endl;

			for (auto line_no : words_map[word])
			{
				cout << "\t" << "(line " << line_no << ")" << lines[line_no] << endl;
			}
		}
		else
		{
			cout << "not found" << endl;
		}
	}
}


int main()
{
	ifstream infile("test_word.txt");
	runQueries(infile);

	system("pause");
	return 0;
}

练习12.29:

12.3.2节练习

练习12.30:

答案见练习练习12.27

练习12.31:

vector按照插入顺序对数据进行排序,set按照字典顺序进行排序,vector可以重复插入相同的数据,对于单词出现次数统计的更精准

练习12.32:

#include<iostream>
#include<vector>
#include<memory>
#include<fstream>
#include<sstream>
#include<set>
#include<map>
using namespace std;

class TextQuery;
class StrBlob
{
public:
	friend class TextQuery;

	StrBlob() : data(make_shared<vector<string>>()) {};
	StrBlob(initializer_list<string> il) : data(make_shared<vector<string>>(il)) {};
	vector<string>::size_type size() const
	{
		return data->size();
	}
	bool empty() const { return data->empty(); };
	void push_back(const string& s)
	{
		data->push_back(s);
	}
	string& front()
	{
		check(0, "front on empty StrBlob");
		return data->front();
	}
	string& back()
	{
		check(0, "back on empty StrBlo");
		return data->back();
	}
	void pop_back()
	{
		check(0, "pop_back on empty StrBlo");
		data->pop_back();
	}
	string& const front() const
	{
		check(0, "const front on empty StrBlob");
		return data->front();
	}
	string& const back() const
	{
		check(0, "const back on empty StrBlob");
		return data->back();
	}

private:
	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);
		}
	}
};


class QueryResult;
class TextQuery
{
public:
	using line_no_type = vector<string>::size_type;
	TextQuery(ifstream& infile)
	{
		// 创建vector<string>容器并使用智能指针管理
		lines_vec = StrBlob();
		string line;
		string word;
		int line_no = 0;
		while (getline(infile, line))
		{
			// 分行保存到vector中
			lines_vec.data->push_back(line);
			istringstream ss(line);
			while (ss >> word)
			{
				// 在单词与行号(set)的map映射中查找单词是否存在
				// 如果存在,在该行号(set)中插入当前行
				// 如果不存在,将这个行号(set)指针指向新创建的set
				auto& line_no_set = this->word_lineno_map[word];
				if (!line_no_set)
				{
					line_no_set.reset(new set<line_no_type>);
				}
				// set容器自带去重、排序
				line_no_set->insert(line_no);
			}
			++line_no;
		}
	}
	void test()
	{
		for (auto temp : *(this->lines_vec.data))
		{
			cout << temp << endl;
		}
	}
	QueryResult query(const string& s);
private:
	StrBlob lines_vec;
	map<string, shared_ptr<set<line_no_type>>> word_lineno_map;
};

class QueryResult
{
	using line_no_type = TextQuery::line_no_type;
	friend ostream& print(ostream& out, const QueryResult& qr);
public:
	QueryResult() = default;
	QueryResult(const string& s, shared_ptr<vector<string>> l, shared_ptr<set<line_no_type>> l_no) :
		word(s), lines(l), lines_no(l_no) {};
private:
	shared_ptr<vector<string>> lines;
	shared_ptr<set<line_no_type>> lines_no;
	const string word;
};

QueryResult TextQuery::query(const string& s)
{
	auto ret = this->word_lineno_map.find(s);
	if (ret != this->word_lineno_map.end())
	{
		return QueryResult(s, this->lines_vec.data, ret->second);
	};
	return QueryResult();
};

ostream& print(ostream& out, const QueryResult& qr)
{
	if (qr.word == "")
	{
		out << "not found word" << endl;
		return out;
	}
	out << qr.word << " occurs " << qr.lines_no->size() << " times " << endl;

	for (auto line_no : *qr.lines_no)
	{
		cout << "\t" << "(line " << line_no << ")" << (*qr.lines)[line_no] << endl;
	}
	return out;
};

void runQueries(ifstream& infile)
{
	TextQuery tq(infile);
	string word;
	//tq.test();
	while (cin >> word)
	{
		print(cout, tq.query(word));
	}
}


int main()
{
	ifstream infile("test_word.txt");
	runQueries(infile);

	system("pause");
	return 0;
}

练习12.33:

#include<iostream>
#include<vector>
#include<memory>
#include<fstream>
#include<sstream>
#include<set>
#include<map>
using namespace std;

class TextQuery;
class StrBlob
{
public:
	friend class TextQuery;

	StrBlob() : data(make_shared<vector<string>>()) {};
	StrBlob(initializer_list<string> il) : data(make_shared<vector<string>>(il)) {};
	vector<string>::size_type size() const
	{
		return data->size();
	}
	bool empty() const { return data->empty(); };
	void push_back(const string& s)
	{
		data->push_back(s);
	}
	string& front()
	{
		check(0, "front on empty StrBlob");
		return data->front();
	}
	string& back()
	{
		check(0, "back on empty StrBlo");
		return data->back();
	}
	void pop_back()
	{
		check(0, "pop_back on empty StrBlo");
		data->pop_back();
	}
	string& const front() const
	{
		check(0, "const front on empty StrBlob");
		return data->front();
	}
	string& const back() const
	{
		check(0, "const back on empty StrBlob");
		return data->back();
	}

private:
	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);
		}
	}
};


class QueryResult;
class TextQuery
{
public:
	using line_no_type = vector<string>::size_type;
	TextQuery(ifstream& infile)
	{
		// 创建vector<string>容器并使用智能指针管理
		lines_vec = StrBlob();
		string line;
		string word;
		int line_no = 0;
		while (getline(infile, line))
		{
			// 分行保存到vector中
			lines_vec.data->push_back(line);
			istringstream ss(line);
			while (ss >> word)
			{
				// 在单词与行号(set)的map映射中查找单词是否存在
				// 如果存在,在该行号(set)中插入当前行
				// 如果不存在,将这个行号(set)指针指向新创建的set
				auto& line_no_set = this->word_lineno_map[word];
				if (!line_no_set)
				{
					line_no_set.reset(new set<line_no_type>);
				}
				// set容器自带去重、排序
				line_no_set->insert(line_no);
			}
			++line_no;
		}
	}
	void test()
	{
		for (auto temp : *(this->lines_vec.data))
		{
			cout << temp << endl;
		}
	}
	QueryResult query(const string& s);
private:
	StrBlob lines_vec;
	map<string, shared_ptr<set<line_no_type>>> word_lineno_map;
};

class QueryResult
{
	using line_no_type = TextQuery::line_no_type;
	friend ostream& print(ostream& out, const QueryResult& qr);
public:
	QueryResult() = default;
	QueryResult(const string& s, shared_ptr<vector<string>> l, shared_ptr<set<line_no_type>> l_no) :
		word(s), lines(l), lines_no(l_no) {};

	shared_ptr<vector<string>> get_file()
	{
		return this->lines;
	}
	set<line_no_type>::iterator cbegin() const
	{
		return (*this->lines_no).begin();
	}
	set<line_no_type>::iterator cend() const
	{
		return (*this->lines_no).end();
	}
private:
	shared_ptr<vector<string>> lines;
	shared_ptr<set<line_no_type>> lines_no;
	const string word;
};

QueryResult TextQuery::query(const string& s)
{
	auto ret = this->word_lineno_map.find(s);
	if (ret != this->word_lineno_map.end())
	{
		return QueryResult(s, this->lines_vec.data, ret->second);
	};
	return QueryResult();
};

ostream& print(ostream& out, const QueryResult& qr)
{
	if (qr.word == "")
	{
		out << "not found word" << endl;
		return out;
	}
	out << qr.word << " occurs " << qr.lines_no->size() << " times " << endl;

	for (auto line_no : *qr.lines_no)
	{
		cout << "\t" << "(line " << line_no << ")" << (*qr.lines)[line_no] << endl;
	}
	return out;
};

void runQueries(ifstream& infile)
{
	TextQuery tq(infile);
	string word;
	//tq.test();
	while (cin >> word)
	{
		print(cout, tq.query(word));
	}
}


int main()
{
	ifstream infile("test_word.txt");
	runQueries(infile);

	system("pause");
	return 0;
}
C++Prime学习笔记 文章被收录于专栏

勇敢和愚蠢只有一剑之差

全部评论

相关推荐

2 2 评论
分享
牛客网
牛客企业服务