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方面:使用一个静态局部对象,避免了频繁创建.