C++Prime 第十二章

C++Prime 第十二章

练习12.1

b2被销毁,其中元素未被销毁,b1和b2包含4个元素.

练习12.2

class StrBlob
{
	typedef std::vector<std::string>::size_type size_type;
	StrBlob();
	StrBlob(std::initializer_list < std::string> il);
	size_type size() const { return data->size(); }
	bool empty()const { return data->empty(); }

	//添加和删除元素
	void push_back(const std::string& t) { data->push_back(t); }
	void pop_back();

	//元素访问
	std::string& front();
	std::string& front()const;
	std::string& back();
	std::string& back()const;
private:
	std::shared_ptr<std::vector<std::string>> data;
	//如果data[i]不合法,抛出一个异常
	void check(size_type i, const std::string& msg) const;
};
#include "StrBlob.h"

StrBlob::StrBlob():data(std::make_shared<std::vector<std::string>>())
{
}

StrBlob::StrBlob(std::initializer_list<std::string> il)
	:data(std::make_shared<std::vector<std::string> >(il))
{
}

void StrBlob::pop_back()
{
	check(0, "pop_back on empty StrBlob");
	data->pop_back();
}

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

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

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

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

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

练习12.3

不需要,push_back 和 pop_back肯定要更改容器的.

练习12.4

i是无符号整数,不为负,没必要检测

练习12.5

优点:可以很方便的直接进行隐私初始化
缺点:隐私转换可能带来意想不到的问题.

练习12.6

vector<int>* new_vector()
{
	return new(nothrow) vector<int>;
}

void fun(vector<int>* a)
{
	int num;
	while (cin >> num)
		a->push_back(num);
}
void fun2(const vector<int>* a)
{
	for (const auto& x : *a)
		cout << x << " ";
	cout << endl;
	delete a;
}
int main()
{
	vector<int>* pvec = new_vector();
	fun(pvec);
	fun2(pvec);

	return 0;
}

练习12.7

shared_ptr<vector<int> > new_vector()
{
	shared_ptr<vector<int> >a(new vector<int>);
	return a;
}

void fun(shared_ptr<vector<int> > a)
{
	int num;
	while (cin >> num)
		a->push_back(num);
}
void fun2(shared_ptr<vector<int> > a)
{
	for (const auto& x : *a)
		cout << x << " ";
	cout << endl;
}
int main()
{
	shared_ptr<vector<int> > p = new_vector();
	fun(p);
	fun2(p);

	return 0;
}

练习12.8

有,返回类型是bool,return的是指针.

练习12.9

r指向了q所指的内存空间,42.r本身的指针空间无人管理,变成了孤儿.
r2被销毁,q2加一

练习12.10

正确,智能指针做函数参数时,会增加引用计数.

练习12.11

错误.p.get()返回一个普通指针,指向p所共享的int对象.利用此指针所创建的shared_ptr,将不会和p形成正确的共享关系,编译器会认为这是两个毫不相干的shared_ptr,尽管它们指向同一内存.当函数释放时,智能指针被释放,共享内存被销毁,导致p成为了空悬指针.
不要用get初始另一个智能指针或为智能指针赋值.

练习12.12

(a)同12.10,是正确的.
(b)错误,智能指针是explicit的,不允许将new int()隐私初始化为shared_ptr
©和b一样的错误
(d)正确.首先生成一个临时的shared_ptr,函数执行结束后销毁.

练习12.13

sp空悬.
首先sp定义为shared_ptr,它指向了int型对象,其值初始化为0
然后p定义为普通变量,指向sp所指对象
最后释放p所指对象,也就导致了sp所指对象被销毁,空间被释放
于是sp空悬.

练习12.14

shared_ptr<connection> p(&c, end_connection);

练习12.15

shared_ptr p(&c, [](connection *p1) {disconnect(*p1); })

练习12.16

	unique_ptr<int> p(new int(10));
	unique_ptr<int> q(new int(11));
	p = q;//无法引用,它是已删除的函数

练习12.17

(a)错误.不能用int来初始化智能指针
(b)错误,非new分配的指针,不能初始化 智能指针.
©正确.
(d)错误.同b
(e)正确
(f)错误,同上.

练习12.18

unique不允许copy和赋值,所以需要release来转移控制权.shared_ptr直接赋值或者复制均可,不用调用这么麻烦.

练习12.19

#pragma once
#include<memory>
#include<iostream>
#include<vector>
#include<exception>
#include "StrBlob.h"
class StrBlobPtr
{
public:
	StrBlobPtr() :curr(0) { }
	StrBlobPtr(StrBlob& a, size_t sz = 0) :wptr(a.data), curr(sz) { }
	std::string& deref() const;
	StrBlobPtr& incr();//前缀递增
private:
	//若检查成功,check返回一个指向vector的shared_ptr
	std::shared_ptr<std::vector<std::string> > check(std::size_t, const std::string&)const;
	//保存一个weak_ptr,意味着底层的vector可能被销毁
	std::weak_ptr<std::vector<std::string>> wptr;
	std::size_t curr;//在数组中的当前位置
};

#include "StrBlobPtr.h"

std::string& StrBlobPtr::deref() const
{
	auto p = check(curr, "dereference past end");
	return (*p)[curr];
}

StrBlobPtr& StrBlobPtr::incr()
{
	check(curr, "increment past end of StrBlobPtr");
	++curr;
	return *this;
}

std::shared_ptr<std::vector<std::string>> StrBlobPtr::check(std::size_t i, const std::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;
}

练习12.20

int main()
{
	StrBlob strblob;
	ifstream fin("word.txt");
	if (!fin)
		throw runtime_error("cann't open file\n");
	string tmp;
	while (getline(fin,tmp))
		strblob.push_back(tmp);
	fin.close();
	StrBlobPtr beg(strblob.begin()),end(strblob.end());
	while (beg != end)
	{
		cout << beg.deref() << endl;
		beg.incr();
	}
	return 0;
}

练习12.21

第一个版本更好.代码逻辑清晰,都写到一行干嘛.又不是行数越少越厉害.

练习12.22

StrBlobPtr(const StrBlob & a,…);//加个const

练习12.23

int main()
{
	char* wordp = new char[100];
	const char* s1 = "hello ";
	const char* s2 = "world";
	strcpy(wordp, s1);
	strcat(wordp, s2);
	cout << wordp << endl;
	delete[]wordp;
	return 0;
}

练习12.24

int main()
{
	string s;
	cin >> s;
	char* ch = new char[s.size() + 1];
	strcpy(ch, s.c_str());
	cout << ch << endl;
	delete[]ch;
	return 0;
}

练习12.25

delete[] pa;

练习12.26

int main()
{
	allocator<string> a;
	auto p = a.allocate(3), q = p;
	string tmp;
	while (cin >> tmp && q != p + 3)
		a.construct(q++, tmp);
	while (q != p)
	{
		cout << *--q << endl;
		a.destroy(q);
	}
	a.deallocate(p, 3);
	return 0;
}

练习12.27

没看后续章节,自己的实现版本.
两个头文件:

#pragma once
#include <iostream>
#include <vector>
#include <set>
#include <map>
#include <algorithm>
#include <iterator>
#include "QueryResult.h"
#include <memory>

class QueryResult;
class TextQuery
{
public:
	typedef std::shared_ptr<std::vector<std::string> > contentType;
	typedef std::shared_ptr<std::map<std::string, std::set<int> > > countType;

public:
	TextQuery(std::ifstream& infile);//必须使用给定文件来初始化
	QueryResult query(const std::string& word);//执行查询

private:
	contentType m_content;//每个元素为输入文件的一行
	countType m_count;//每个单词出现的行号
};


#pragma once
#include "TextQuery.h"
#include <memory>
class QueryResult
{
public:
	typedef std::vector<std::string>  contentType;
	typedef std::map<std::string, std::set<int> >  countType;

public:
	QueryResult(std::shared_ptr<contentType> p,std::shared_ptr<countType> q,const std::string & word);//必须显示初始化

private:
	bool m_find = false;//是否查询到单词
	std::string m_word ;//待查询的单词
	std::size_t m_cnt = 0;//单词出现的总次数
	std::shared_ptr<contentType> m_content ;//指向文本的指针
	std::shared_ptr<countType> m_count;//指向map的指针
	std::map<std::string,std::set<int> >::iterator m_count_it ;//指向行号的迭代器

	friend std::ostream& print(std::ostream& os, const QueryResult& qr);
};
std::ostream& print(std::ostream& os, const QueryResult& qr);

两个源文件:

#include "QueryResult.h"
#include <algorithm>
std::ostream& print(std::ostream& os, const QueryResult& qr)
{
	if (!qr.m_find)
	{
		os << "not found " << qr.m_word << std::endl;
		return os;
	}
	os << qr.m_word << " occurs " << qr.m_cnt << " times" << std::endl;
	for (auto it = qr.m_count_it->second.begin(); it != qr.m_count_it->second.end(); ++it)
	{
		std::cout << "(line " << *it << ") " << (*qr.m_content)[*it - 1] << std::endl;
	}
	return os;
}

QueryResult::QueryResult(std::shared_ptr<contentType> p, std::shared_ptr<countType> q, const std::string& word)
:m_count(q)
{
	auto pos = m_count->find(word);
	if (pos == m_count->end())//没找到word
		m_find = false;
	else
	{
		m_find = true;
		m_word = word;
		m_count_it = pos;
		m_content = p;
		for (auto it = pos->second.begin(); it != pos->second.end(); ++it)
			m_cnt++;
	}
}

#include "TextQuery.h"
#include <fstream>
#include <exception>
#include <string>
#include <sstream>
TextQuery::TextQuery(std::ifstream& fin):m_content(new std::vector<std::string>),
	m_count(new std::map<std::string,std::set<int> >)
{
	std::string line;
	size_t line_num = 0;
	while (getline(fin, line))
	{
		m_content->push_back(line);//按行号存入每一行
		std::istringstream sin(line);
		std::string word;
		while (sin >> word)//对每行中每个单词
		{
			std::set<int> s;
			//if ((m_count->find(word)) == m_count->end())
			//	(*m_count)[word] = s;
			(*m_count)[word].insert(line_num + 1);//关键,插入单词所在行号
		}
		line_num++;//读下一行
	}
	//for (auto it = m_count->begin(); it != m_count->end(); ++it)
	//{
	//	std::cout << it->first << "出现在: ";
	//	for (auto iter = it->second.begin(); iter != it->second.end(); ++iter)
	//		std::cout << *iter << " ";
	//	std::cout << std::endl;
	//}
}

QueryResult TextQuery::query(const std::string &word)
{
	QueryResult tmp(m_content, m_count, word);
	return tmp;
}


练习12.28

练习12.29

不再做了.

练习12.30

#include <map>
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <vector>
#include<iterator>
#include <algorithm>
#include<memory>
#include "TextQuery.h"
using namespace std;

void runQueties(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()
{
	ifstream fin("word.txt");
	if (!fin)
		throw runtime_error("cann't open ""word.txt");
	runQueties(fin);

	return 0;
}

练习12.31

vector会出现重复,同一行单词多次出现的话,就会出现差错,和题意不符,另外也少了自动排序的功能.

练习12.32

练习12.33

#pragma once
#include "TextQuery.h"
#include <memory>
#include <set>
#include <memory>
class QueryResult
{
public:
	typedef std::vector<std::string>  contentType;
	typedef std::set<int>   countType;

public:
	QueryResult(std::shared_ptr<contentType> p, std::shared_ptr<countType> q, const std::string& word)
		:m_content(p), m_count(q), m_word(word) { }
	
	countType::iterator begin(const std::string& str) { return m_count->begin(); }
	countType::iterator end(const std::string& str) { return m_count->end(); }
	std::shared_ptr<contentType> get_file()const { return m_content; }

private:
	std::string m_word ;//待查询的单词
	std::shared_ptr<contentType> m_content ;//指向文本的指针
	std::shared_ptr<countType> m_count;//指向行号的指针

	friend std::ostream& print(std::ostream& os, const QueryResult& qr);
};
std::ostream& print(std::ostream& os, const QueryResult& qr);

#pragma once
#include <iostream>
#include <vector>
#include <set>
#include <map>
#include <algorithm>
#include <iterator>
#include "QueryResult.h"
#include <memory>

class QueryResult;
class TextQuery
{
public:
	typedef std::shared_ptr<std::vector<std::string> > contentType;
	typedef std::map<std::string, std::shared_ptr<std::set<int> > > countType;

public:
	TextQuery(std::ifstream& infile);//必须使用给定文件来初始化
	QueryResult query(const std::string& word) const;//执行查询

private:
	contentType m_content;//每个元素为输入文件的一行
	countType m_count;//每个单词出现的行号
};


#include "TextQuery.h"
#include <fstream>
#include <exception>
#include <string>
#include <sstream>
TextQuery::TextQuery(std::ifstream& fin):m_content(new std::vector<std::string>)
{
	std::string line;
	size_t line_num = 0;
	while (getline(fin, line))
	{
		m_content->push_back(line);//按行号存入每一行
		std::istringstream sin(line);
		std::string word;
		while (sin >> word)//对每行中每个单词
		{
			auto& lines = m_count[word];//lines 是一个shared_ptr
			if (!lines)
				lines.reset(new std::set<int>);
			lines->insert(line_num);//关键,插入单词所在行号
		}
		line_num++;//读下一行
	}
	//for (auto it = m_count->begin(); it != m_count->end(); ++it)
	//{
	//	std::cout << it->first << "出现在: ";
	//	for (auto iter = it->second.begin(); iter != it->second.end(); ++iter)
	//		std::cout << *iter << " ";
	//	std::cout << std::endl;
	//}
}

QueryResult TextQuery::query(const std::string &word)const
{
	//未找到word,返回一个指向此set的指针
	static std::shared_ptr<std::set<int>> nodata(new std::set<int>);

	auto loc = m_count.find(word);//loc 是一个pair
	if (loc == m_count.end())
		return QueryResult(m_content, nodata, word);
	else
		return QueryResult(m_content, loc->second, word);
}


#include "QueryResult.h"
#include <algorithm>
std::ostream& print(std::ostream& os, const QueryResult& qr)
{
	os << qr.m_word << " occurs " << qr.m_count->size() << " times" << std::endl;
	for (auto num : *qr.m_count)
		os << "\t(line " << num + 1 << " )"
		<< *(qr.m_content->begin() + num) << std::endl;
	return os;
}


OK了,这是学习书上后改进的版本.
保存行号方面,不再保存整个map而是仅仅保存包含查询结果的set的shared_ptr,节省了空间,更方便的获得查询结果.
返回空vector方面:使用一个静态局部对象,避免了频繁创建.

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值