《C++primer(第五版)》学习之路-第十二章:动态内存

 声明:版权所有,转载请标明出处,请勿用于商业用途。  联系信箱:libin493073668@sina.com


12.1 动态内存与智能指针


1.在C++中,动态内存的管理是通过一对运算符来完成:new,在动态内存中为对象分配空间并返回一个指向该对象的指针,我们可以选择对对象进行初始化;delete,接受一个动态对象的指针,销毁该对象,并释放与之关联的内存。


2.

shared_ptr允许多个指针指向同一个对象;unique_ptr则“独占”所指向的对象。标准库还定义了一个名为weak_ptr的伴随类,它是一种弱引用,指向shared_ptr所管理的对象。这三种类型都定义在memory头文件中。


3.

shared_ptr和unique_ptr都支持的操作

shared_ptr<T> sp

unique_ptr<T> up          空智能指针,可以指向类型为T的对象

p                                     将p用作一个条件判断,若p指向一个对象,则为true

*p                                    解引用p,获得它指向的对象

p->mem                          等价于(*p).mem

p.get()                            返回p中保存的指针。要小心使用,若智能指针释放了其对象,返回的指针所指向的对象也就消失了。

swap(p,q)

p.swap(q)                       交换p和q中的指针


4.

shared_ptr独有的操作

make_shared<T>(args)      返回一个shared_ptr,指向一个动态分配的类型为T的对象。使用args初始化对象。

make_shared<T>p(q)         p是shared_ptr  q的拷贝;此操作会递增q中的计数器。q中的指针必须能转换为T*

p = q                                    p和q都是shared_ptr,所保存的指针必须能相互转换。此操作会递减p的引用计数,递增q的引用计数;若p的引用计数变为0,则将其管理的原内存释放。

p.unique()                           若p.use_count()为1,返回true;否则返回false

p.use_count()                     返回与p共享对象的智能指针数量;可能很慢,主要用于测试


5.

由内置指针(而不是智能指针)管理的动态内存在被显式释放以前一直都会存在。


6.

定义和改变shared_ptr的其他方法

shared_ptr<T> p(q)           p管理内置指针q所指向的对象;q必须指向new分配的内存,且能够转换为T*类型

shared_ptr<T> p(u)           p从unique_ptr u那里接管了对象的所有权,将u置为空

shared_ptr<T> p(q,d)        p接管了内置指针q所指向的对象的所有权。q必须能转换为T*类型。p将使用可调用对象d来代替delete

shared_ptr<T> p(p2,d)      p是shared_ptr p2的拷贝,唯一的区别是p将用可调用对象d来代替delete

p.reset()                             

p.reset(q)

p.reset(q,d)                        若p是唯一指向其对象的shared_ptr,reset会释放此对象。若传递了可选的参数内置指针q,会令p指向q,否则会将p置为空。若还传递了参数d,将会调用d而不是delete来释放q


7.

为了正确使用智能指针,我们必须坚持一些基本规范

⑴不使用相同的内置指针值初始化(或reset)多个智能指针

⑵不delete get()返回的指针

⑶不使用get()初始化或reset另一个智能指针

⑷如果你使用get()返回的指针,记住当最后一个对应的智能指针销毁后,你的指针就变成无效了

⑸如果你使用智能指针管理的资源不是new分配的内存,记住传递给它一个删除器


8.

unique_ptr操作

unique_ptr<T> u1          

unique_ptr<T,p> u2         空unique_ptr,可以指向类型为T的对象。u1会使用delete来释放它的指针;u2会使用一个类型为D的可调用对象来释放它的指针

unique_ptr<T,p> u(d)       空unique_ptr,指向类型为T的对象,用类型为D的对象d代替delete

u = nullptr                         释放u所指向的对象,将u置为空

u.release                          u放弃对指针的控制权,返回指针,并将u置为空

u.reset()                           释放u指向的对象

u.reset(q)

u.reset(nullptr)                 如果提供了内置指针q,令u指向这个对象;否则将u置为空


9.

weak_ptr操作

weak_ptr<T> w             空weak_ptr可以指向类型为T的对象

weak_ptr<T> w(sp)       与shared_ptr sp指向相同对象的weak_ptr。T必须能转换为sp指向的类型。

w = p                              p可以是一个shared_ptr或一个weak_ptr。赋值后w与p共享对象

w.reset()                         将w置为空

w.use_count()                与w共享对象的shared_ptr的数量

w.expired()                     若w.use_count()为0,返回true,否则返回false

w.lock()                          如果expired为true,返回一个空shared_ptr;否则返回一个指向w的对象的shared_ptr


12.2 动态数组


1.动态数组并不是数组类型,而是得到一个数组元素类型的指针。


2.

指向数组的unique_ptr

指向数组的unique_ptr不支持成员访问运算符

其他unique_ptr操作不变

unique_ptr<T[]> u          u可以指向一个动态分配的数组,数组元素类型为T

unique_ptr<T[]> u(p)     u指向内置指针p所指向的动态分配的数组。p必须能转换为类型T*

u[i]                                 返回u拥有的数组中位置i处的对象,u必须指向一个数组


3.标准库allocator类定义在头文件memory中,它帮助我们将内存分配和对象构造分离开来。它提供一种类型感知的内存分配方法,它分配的内存是原始的,未构造的。


4.

标准库allocator类及其算法

allocator<T> a           定义了一个名为a的allocator对象,它可以为类型为T的对象分配内存

a.allocator(n)             分配一段原始的,未构造的内存,保存n个类型为T的对象

a.deallocate(p,n)       释放从T*指针p中地址开始的内存,这块内存保存了n个类型为T的对象;p必须是一个先前由allocate返回的指针,且n必须是p创建时所要求的大小。在调用deallocate之前,用户必须对每个在这块内存中创建的对象调用destory。

a.construct(p,args)    p必须是一个类型为T*的指针,指向一块原始内存;arg被传递给类型为T的构造函数,用来在p指向的内存中构造一个对象

a.destroy(p)              p为T*类型的指针,此算法对p指向的对象指向析构函数


5.

allocator算法

这些函数在给定目的位置创建元素,而不是由系统分配内存给它们。

uninitialized_copy(b,e,b2)         从迭代器b和e指出的输入范围中拷贝元素到迭代器b2指定的未构造的原始内存中。b2指向的内存必须足够大,能容纳输入序列中元素的拷贝

uninitialized_copy_n(b,n,b2)     从迭代器b指向的元素开始,拷贝n个元素到b2开始的内存中

uninitialized_fill(b,e,t)                在迭代器b和e指定的原始内存范围中创建对象,对象的值均为t的拷贝

uninitialized_fill_n(b,n,t)            从迭代器b指向的内存地址开始创建n个对象。b必须指向足够大的未构造的原始内存,能够容纳给定数量的对象


PS:部分练习答案


练习12.1

b2被销毁,但是b2里面的元素不会被销毁,所以b1,b2都有4个元素


练习12.2

ex12_02.h

#include <vector>
#include <string>
#include <initializer_list>
#include <memory>
#include <exception>

using std::vector;
using std::string;

class StrBlob
{
	public:
		using size_type = vector<string>::size_type;

		StrBlob():data(std::make_shared<vector<string>>()) {}
		StrBlob(std::initializer_list<string> il):data(std::make_shared<vector<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()
		{
			check(0,"pop_back on empty StrBlob");
			data->pop_back();
		}

		std::string& front()
		{
			check(0,"front on empty StrBlob");
			return data->front();
		}

		std::string& back()
		{
			check(0,"back on empty StrBlob");
			return data->back();
		}

		const std::string& front() const
		{
			check(0,"front on empty StrBlob");
			return data->front();
		}

		const std::string& back() const
		{
			check(0,"back on empty StrBlob");
			return data->back();
		}

	private:
		void check(size_type i,const string& msg) const
		{
			if(i>=data->size())
				throw std::out_of_range(msg);
		}
	private:
		std::shared_ptr<vector<string>> data;
};

text.cpp

#include <iostream>
#include "ex12_02.h"

int main()
{
	const StrBlob csb{"one","two","three"};
	StrBlob sb{"one","two","four"};
	
	std::cout << csb.front() << " " << csb.back() << std::endl;
	sb.back() = "three";
	std::cout << sb.front() << " " << sb.back() << std::endl;
}

练习12.6

#include <iostream>
#include <vector>
#include <string>
#include <memory>

std::vector<int>* dynamic_vector_generator()
{
	std::vector<int>* ptr_v = new std::vector<int>();
	return ptr_v;
}

void dynamic_vector_processor(std::vector<int>* ptr_v)
{
	int i;
	std::cout << "please enter:" << std::endl;
	while(std::cin >> i && i!=999)
		ptr_v->push_back(i);
}

void dynamic_vector_printer(std::vector<int>* ptr_v)
{
	for(const auto& elem: *ptr_v)
		std::cout << elem << " ";
	std::cout << std::endl;
}

int main()
{
	std::vector<int>* ptr_vi = dynamic_vector_generator();
	dynamic_vector_processor(ptr_vi);
	dynamic_vector_printer(ptr_vi);
	delete ptr_vi;
	return 0;
}

练习12.7

#include <iostream>
#include <vector>
#include <string>
#include <memory>

std::shared_ptr<std::vector<int>> dynamic_vector_generator_sptr()
{
	return std::make_shared<std::vector<int>>();
}

void dynamic_vector_processor_sptr(std::shared_ptr<std::vector<int>> sptr_vi)
{
	int i;
	std::cout << "please enter:" << std::endl;
	while(std::cin >> i && i!=999)
		sptr_vi->push_back(i);
}

void dynamic_vector_printer_sptr(const std::shared_ptr<std::vector<int>> sptr_vi)
{
	for(const auto& elem: *sptr_vi)
	std::cout << elem << " ";
	std::cout << std::endl;
}

int main()
{
	auto sptr = dynamic_vector_generator_sptr();
	dynamic_vector_processor_sptr(sptr);
	dynamic_vector_printer_sptr(sptr);
	return 0;
}

练习12.14

#include <iostream>
#include <string>
#include <memory>

struct connection
{
	std::string ip;
	int port;
	connection(std::string ip_,int port_):ip(ip_),port(port_){}
};

struct destination
{
	std::string ip;
	int port;
	destination(std::string ip_,int port_):ip(ip_),port(port_){}
};

connection connect(destination* pDest)
{
	std::shared_ptr<connection> pConn(new connection(pDest->ip,pDest->port));
	std::cout << "creating connection(" << pConn.use_count() << ")" << std::endl;
	return *pConn;
}

void disconnect(connection pConn)
{
	std::cout << "connection close(" << pConn.ip << ":" << pConn.port << ")" << std::endl;
}

void end_connection(connection* pConn)
{
	disconnect(*pConn);
}

void f(destination& d)
{
	connection conn = connect(&d);
	std::shared_ptr<connection> p(&conn,end_connection);
	std::cout << "connection now(" << p.use_count() << ")" << std::endl;
}

int main()
{
	destination dest("202.118.176.67",3316);
	f(dest);
	
	return 0;
}

练习12.15

#include <iostream>
#include <string>
#include <memory>

struct connection
{
	std::string ip;
	int port;
	connection(std::string ip_,int port_):ip(ip_),port(port_){}
};

struct destination
{
	std::string ip;
	int port;
	destination(std::string ip_,int port_):ip(ip_),port(port_){}
};

connection connect(destination* pDest)
{
	std::shared_ptr<connection> pConn(new connection(pDest->ip,pDest->port));
	std::cout << "creating connection(" << pConn.use_count() << ")" << std::endl;
	return *pConn;
}

void disconnect(connection pConn)
{
	std::cout << "connection close(" << pConn.ip << ":" << pConn.port << ")" << std::endl;
}

void f(destination& d)
{
	connection conn = connect(&d);
	std::shared_ptr<connection> p(&conn,[](connection* pConn){disconnect(*pConn);});
	std::cout << "connection now(" << p.use_count() << ")" << std::endl;
}

int main()
{
	destination dest("202.118.176.67",3316);
	f(dest);
	
	return 0;
}

练习12.19

ex12_19.h

#ifndef CP5_ex12_19_h
#define CP5_ex12_19_h

#include <vector>
#include <string>
#include <initializer_list>
#include <memory>
#include <exception>

using std::vector;
using std::string;

class StrBlobPtr;

class StrBlob
{
	public:
		using size_type = vector<string>::size_type;
		friend class StrBlobPtr;

		StrBlobPtr begin();
		StrBlobPtr end();
		
		StrBlob():data(std::make_shared<vector<string>>()) {}
		StrBlob(std::initializer_list<string> il):data(std::make_shared<vector<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()
		{
			check(0,"pop_back on empty StrBlob");
			data->pop_back();
		}

		std::string& back()
		{
			check(0, "back on empty StrBlob");
			return data->back();
		}

		const std::string& front() const
		{
			check(0, "front on empty StrBlob");
			return data->front();
		}
		const std::string& back() const
		{
			check(0, "back on empty StrBlob");
			return data->back();
		}
		
	private:
		void check(size_type i,const string& msg) const
		{
			if(i>=data->size())
			throw std::out_of_range(msg);
		}
		
	private:
		std::shared_ptr<vector<string>> data;
};

class StrBlobPtr
{
	public:
		StrBlobPtr():curr(0){}
		StrBlobPtr(StrBlob& a,size_t sz = 0):wptr(a.data),curr(sz){}
		bool operator!=(const StrBlobPtr& p)
		{
			return p.curr!=curr;
		}
		string& deref()const
		{
			auto p = check(curr,"dereference past end");
			return (*p)[curr];
		} 
		StrBlobPtr& incr()
		{
			check(curr,"increament past end of StrBlobPtr");
			++curr;
			return *this;
		}
	
	private:
		std::shared_ptr<vector<string>> check(size_t i,const string& msg) const
		{
			auto ret = wptr.lock();
			if(!ret)
			throw std::runtime_error("unbound StrBlobPtr");
			if(i>=ret->size())
			throw std::out_of_range(msg);
			return ret;
		}
		
		std::weak_ptr<vector<string>> wptr;
		size_t curr;
};

#endif

ex12_19.cpp

#include "ex12_19.h"

StrBlobPtr StrBlob::begin()
{
	return StrBlobPtr(*this);
}

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

练习12.20

#include "ex12_19.h"
#include <fstream>
#include <iostream>

int main()
{
	std::ifstream ifs("book.txt");
	StrBlob blob;
	for(std::string str; std::getline(ifs,str);)
		blob.push_back(str);
	for(StrBlobPtr pbeg(blob.begin()),pend(blob.end()); pbeg!=pend; pbeg.incr())
		std::cout<<pbeg.deref()<<std::endl;
}

练习12.22

ex12_22.h

#ifndef CP5_ex12_22_h
#define CP5_ex12_22_h

#include <vector>
#include <string>
#include <initializer_list>
#include <memory>
#include <exception>

using std::vector;
using std::string;

class ConstStrBlobPtr;

class StrBlob
{
	public:
		using size_type = vector<string>::size_type;
		friend class ConstStrBlobPtr;

		StrBlobPtr begin() const;
		StrBlobPtr end() const;

		StrBlob():data(std::make_shared<vector<string>>()) {}
		StrBlob(std::initializer_list<string> il):data(std::make_shared<vector<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()
		{
			check(0,"pop_back on empty StrBlob");
			data->pop_back();
		}

		std::string& back()
		{
			check(0, "back on empty StrBlob");
			return data->back();
		}

		const std::string& front() const
		{
			check(0, "front on empty StrBlob");
			return data->front();
		}
		const std::string& back() const
		{
			check(0, "back on empty StrBlob");
			return data->back();
		}

	private:
		void check(size_type i,const string& msg) const
		{
			if(i>=data->size())
				throw std::out_of_range(msg);
		}

	private:
		std::shared_ptr<vector<string>> data;
};

class ConstStrBlobPtr
{
	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,"increament past end of StrBlobPtr");
			++curr;
			return *this;
		}

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

		std::weak_ptr<vector<string>> wptr;
		size_t curr;
};

#endif

ex12_22.cpp

#include "ex12_19.h"

ConstStrBlobPtr StrBlob::begin() const
{
	return ConstStrBlobPtr(*this);
}

ConstStrBlobPtr StrBlob::end() const
{
	return ConstStrBlobPtr(*this,data->size());
}

练习12.23

#include <iostream>
#include <string>
#include <cstring>

int main()
{
	char *concatenate_string = new char[255]();
	strcat(concatenate_string,"hello ");
	strcat(concatenate_string,"world");
	std::cout << concatenate_string << std::endl;
	delete[] concatenate_string;
	
	std::string str1{"hello "},str2{"world"};
	std::cout << str1+str2 << std::endl;
}

练习12.24

#include <iostream>

int main()
{
	std::cout << "How long do you want the string? ";
	int size {0};
	std::cin >> size;
	char* input = new char[size + 1]();
	std::cin.ignore();
	std::cout << "input the string: ";
	std::cin.get(input, size + 1);
	std::cout << input;
	delete[] input;
}

练习12.26

#include <iostream>
#include <string>
#include <memory>

void input_reverse_output_string(int n)
{
	std::allocator<std::string> alloc;
	auto const p = alloc.allocate(n);
	std::string s;
	auto q = p;
	while(std::cin >> s && q!=p+n) alloc.construct(q++,s);
	while(q!=p)
	{
		std::cout << *--q << " ";
		alloc.destroy(q);
	}
	alloc.deallocate(p,n);
}

int main()
{
	input_reverse_output_string(5);
	return 0;
}

练习12.27 & 12.30

ex12_27_30.h

#ifndef CP5_ex12_27_h
#define CP5_ex12_27_h

#include <string>
using std::string;

#include <vector>
using std::vector;

#include <memory>
using std::shared_ptr;

#include <iostream>
#include <fstream>
#include <map>
#include <set>

class QueryResult;
class TextQuery
{
	public:
		using LineNo = vector<string>::size_type;
		TextQuery(std::ifstream&);
		QueryResult query(const string&) const;

	private:
		shared_ptr<vector<string>> input;
		std::map<string, shared_ptr<std::set<LineNo>>> result;
};

class QueryResult
{
	public:
		friend std::ostream& print(std::ostream&, const QueryResult&);

	public:
		QueryResult(const string& s, shared_ptr<std::set<TextQuery::LineNo>> set,
		            shared_ptr<vector<string>> v)
			: word(s), nos(set), input(v)
		{
		}

	private:
		string word;
		shared_ptr<std::set<TextQuery::LineNo>> nos;
		shared_ptr<vector<string>> input;
};

std::ostream& print(std::ostream&, const QueryResult&);

#endif

ex12_27_30.cpp

#include "ex12_27_30.h"
#include <sstream>
#include <algorithm>

TextQuery::TextQuery(std::ifstream& ifs) : input(new vector<string>)
{
	LineNo lineNo {0};
	for (string line; std::getline(ifs, line); ++lineNo)
	{
		input->push_back(line);
		std::istringstream line_stream(line);
		for (string text, word; line_stream >> text; word.clear())
		{
			std::remove_copy_if(text.begin(), text.end(),
			                    std::back_inserter(word), ispunct);
			auto& nos = result[word];
			if (!nos) nos.reset(new std::set<LineNo>);
			nos->insert(lineNo);
		}
	}
}

QueryResult TextQuery::query(const string& str) const
{
	static shared_ptr<std::set<LineNo>> nodate(new std::set<LineNo>);
	auto found = result.find(str);
	if (found == result.end())
		return QueryResult(str, nodate, input);
	else
		return QueryResult(str, found->second, input);
}

std::ostream& print(std::ostream& out, const QueryResult& qr)
{
	out << qr.word << " occurs " << qr.nos->size()
	    << (qr.nos->size() > 1 ? " times" : " time") << std::endl;
	for (auto i : *qr.nos)
		out << "\t(line " << i + 1 << ") " << qr.input->at(i) << std::endl;
	return out;
}

text.cpp

#include "ex12_27_30.h"
#include <iostream>

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

int main()
{
	std::ifstream file("<span style="color: rgb(24, 54, 145); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; line-height: 16px; white-space: pre;">storyDataFile</span>.txt");
	runQueries(file);
}

练习12.28

#include <string>
#include <vector>
#include <memory>
#include <iostream>
#include <fstream>
#include <sstream>
#include <map>
#include <set>
#include <algorithm>

using std::string;
using std::vector;
using std::shared_ptr;

int main()
{
	std::ifstream file("letter.txt");
	vector<string> input;
	std::map<string, std::set<decltype(input.size())>> dictionary;
	decltype(input.size()) lineNo {0};

	for (string line; std::getline(file, line); ++lineNo)
	{
		input.push_back(line);
		std::istringstream line_stream(line);
		for (string text, word; line_stream >> text; word.clear())
		{
			std::remove_copy_if(text.begin(), text.end(),
			                    std::back_inserter(word), ispunct);
			dictionary[word].insert(lineNo);
		}
	}

	while (true)
	{
		std::cout << "enter word to look for, or q to quit: ";
		string s;
		if (!(std::cin >> s) || s == "q") break;
		auto found = dictionary.find(s);
		if (found != dictionary.end())
		{
			std::cout << s << " occurs " << found->second.size()
			          << (found->second.size() > 1 ? " times" : " time")
			          << std::endl;
			for (auto i : found->second)
				std::cout << "\t(line " << i + 1 << ") " << input.at(i)
				          << std::endl;
		}
		else
			std::cout << s << " occurs 0 time" << std::endl;
	}
}

练习12.32

ex12_32.h

#ifndef CP5_ex12_32_h
#define CP5_ex12_32_h

#include "ex12_22.h"
using std::shared_ptr;

#include <iostream>
#include <fstream>
#include <map>
#include <set>

class QueryResult;
class TextQuery
{
	public:
		TextQuery(std::ifstream&);
		QueryResult query(const string&) const;

	private:
		shared_ptr<StrBlob> input;
		std::map<string, shared_ptr<std::set<StrBlob::size_type>>> result;
};

class QueryResult
{
	public:
		friend std::ostream& print(std::ostream&, const QueryResult&);

	public:
		QueryResult(const string& s, shared_ptr<std::set<StrBlob::size_type>> set,
		            shared_ptr<StrBlob> v)
			: word(s), nos(set), input(v)
		{
		}

	private:
		string word;
		shared_ptr<std::set<StrBlob::size_type>> nos;
		shared_ptr<StrBlob> input;
};

std::ostream& print(std::ostream&, const QueryResult&);

#endif

ex12_32.cpp

#include "ex12_32.h"
#include <sstream>
#include <algorithm>

TextQuery::TextQuery(std::ifstream& ifs) : input(new StrBlob)
{
	StrBlob::size_type lineNo {0};
	for (string line; std::getline(ifs, line); ++lineNo)
	{
		input->push_back(line);
		std::istringstream line_stream(line);
		for (string text, word; line_stream >> text; word.clear())
		{
			std::remove_copy_if(text.begin(), text.end(),
			                    std::back_inserter(word), ispunct);
			auto& nos = result[word];
			if (!nos) nos.reset(new std::set<StrBlob::size_type>);
			nos->insert(lineNo);
		}
	}
}

QueryResult TextQuery::query(const string& str) const
{
	static shared_ptr<std::set<StrBlob::size_type>> nodate(
	            new std::set<StrBlob::size_type>);
	auto found = result.find(str);
	if (found == result.end())
		return QueryResult(str, nodate, input);
	else
		return QueryResult(str, found->second, input);
}

std::ostream& print(std::ostream& out, const QueryResult& qr)
{
	out << qr.word << " occurs " << qr.nos->size()
	    << (qr.nos->size() > 1 ? " times" : " time") << std::endl;
	for (auto i : *qr.nos)
	{
		ConstStrBlobPtr p(*qr.input, i);
		out << "\t(line " << i + 1 << ") " << p.deref() << std::endl;
	}
	return out;
}

练习12.33

ex12_33.h

#ifndef CP5_ex12_33_h
#define CP5_ex12_33_h

#include "ex12_22.h"
using std::shared_ptr;

#include <iostream>
#include <fstream>
#include <map>
#include <set>

class QueryResult;
class TextQuery
{
	public:
		TextQuery(std::ifstream&);
		QueryResult query(const string&) const;

	private:
		shared_ptr<StrBlob> input;
		std::map<string, shared_ptr<std::set<StrBlob::size_type>>> result;
};

class QueryResult
{
	public:
		using ResultIter = std::set<StrBlob::size_type>::iterator;
		friend std::ostream& print(std::ostream&, const QueryResult&);

	public:
		QueryResult(const string& s, shared_ptr<std::set<StrBlob::size_type>> set,
		            shared_ptr<StrBlob> v)
			: word(s), nos(set), input(v)
		{
		}
		ResultIter begin() const
		{
			return nos->begin();
		}
		ResultIter end() const
		{
			return nos->end();
		}
		shared_ptr<StrBlob> get_file() const
		{
			return input;
		}
	private:
		string word;
		shared_ptr<std::set<StrBlob::size_type>> nos;
		shared_ptr<StrBlob> input;
};

std::ostream& print(std::ostream&, const QueryResult&);

#endif

ex12_33.cpp

#include "ex12_33.h"
#include <sstream>
#include <algorithm>

TextQuery::TextQuery(std::ifstream& ifs) : input(new StrBlob)
{
	StrBlob::size_type lineNo {0};
	for (string line; std::getline(ifs, line); ++lineNo)
	{
		input->push_back(line);
		std::istringstream line_stream(line);
		for (string text, word; line_stream >> text; word.clear())
		{
			std::remove_copy_if(text.begin(), text.end(),
			                    std::back_inserter(word), ispunct);
			auto& nos = result[word];
			if (!nos) nos.reset(new std::set<StrBlob::size_type>);
			nos->insert(lineNo);
		}
	}
}

QueryResult TextQuery::query(const string& str) const
{
	static shared_ptr<std::set<StrBlob::size_type>> nodate(
	            new std::set<StrBlob::size_type>);
	auto found = result.find(str);
	if (found == result.end())
		return QueryResult(str, nodate, input);
	else
		return QueryResult(str, found->second, input);
}

std::ostream& print(std::ostream& out, const QueryResult& qr)
{
	out << qr.word << " occurs " << qr.nos->size()
	    << (qr.nos->size() > 1 ? " times" : " time") << std::endl;
	for (auto it = qr.begin(); it != qr.end(); ++it)
	{
		ConstStrBlobPtr p(*qr.get_file(), *it);
		out << "\t(line " << *it + 1 << ") " << p.deref() << std::endl;
	}
	return out;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值