C++ Primer课后习题解答(第十二章)

Exercises Section 12.1.1

Ex12.1

// b1 和 b2 共享数据,故而 b1 和 b2 都有 4 个元素
StrBlob b1;
{
	Strblob b2 = {"a", "an", "the"};
	b1 = b2;
	b2.push_back("about");
}

Ex12.2

class StrBlob 
{
public:
    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(); }
    // add and remove elements
    void push_back(const std::string &t) { data->push_back(t); }
    void pop_back();
    // element access
    std::string &front();
    std::string &back();
private:
    std::shared_ptr<std::vector<std::string>> data;
    // throws msg if data[i] isn't valid
    void check(size_type i, const std::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()
{
    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();
}

Ex12.3

不需要;push_back 和 pop-back 会改变元素数量,故而不能定义 const 版本

Ex12.4

完全OK;size_type 类型为 unsigned 类型

Ex12.5

explicit 使构造函数显式化,优点是排除了隐式转换带来的一系列错误问题,缺点是降低了程序的灵活性。

Exercises Section 12.1.2

Ex12.6

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

using namespace std;

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

void add_element(vector<int> *fac)
{
    int i = 0;
    while (std::cin >> i)
        fac->push_back(i);
}

void print_element(vector<int> *fac)
{
    for (const auto &i: *fac)
        std::cout << i << " ";
    std::cout << endl;
}

int main()
{
    auto pv = fac();
    cout << "input some numbers: ";
    add_element(pv);
    print_element(pv);
    delete pv;
    system("pause");
    return 0;
}

Ex12.7

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

using namespace std;

shared_ptr<vector<int>> fac()
{
    return make_shared<vector<int>>();
}

void add_element(shared_ptr<vector<int>> fac)
{
    int i = 0;
    while (std::cin >> i)
        fac->push_back(i);
}

void print_element(shared_ptr<vector<int>> fac)
{
    for (const auto &i: *fac)
        std::cout << i << " ";
    std::cout << endl;
}

int main()
{
    auto pv = fac();
    cout << "input some numbers: ";
    add_element(pv);
    print_element(pv);
    system("pause");
    return 0;
}

Ex12.8


bool b() 
{
	int *p = new int;	// 如果 new 失败,那么抛出 std::bad_alloc 异常
	// 修改代码:int *p = new (nothrow) int;
	// ...
	return p;
}

Ex12.9

// q 和 r 使用 new 方法,如果内存未及时释放,会造成内存泄漏
int *q = new int(42), *r = new int(100);
r = q;
// q2 和 r2 使用智能指针,当把 q2 的值赋给 r2 时,q2 的引用计数增 1 而 r2 的引用计数减 1 变为 0,自动释放内存
auto q2 = make_shared<int>(42), r2 = make_shared<int>(100);
r2 = q2;

Exercises Section 12.1.3

Ex12.10

// 正确
shared_ptr<int> p(new int(42));
proces(shared_ptr<int>(p));

Ex12.11

// get函数会得到一个内置指针,指向动态指针 p 管理的对象;将其作为参数传入 process 函数中则有两个独立的动态指针指向同一个对象;
// 当 process 结束后, p 指针的内存也释放了
process(shared_ptr<int>(p.get()));

Ex12.12

auto p = new int();
auto sp = make_shared<int>();

a) process(sp);		// 合法;将智能指针 sp 副本传入 process 函数中
b) process(new int());	// 不合法;普通指针不能隐式转换为智能指针
c) process(p);	// 不合法;与 b 一样
d) process(shared_ptr(int)(p));		// 合法;将普通指针显式转换为智能指针,然后将智能指针副本传入 process

Ex12.13

// delete 只和 new 需要成对出现,不能用 delete 去释放 shared_ptr 内存,故而此代码会发生错误
auto sp = make_shared<int>();
auto p = sp.get();
delete p;

Exercises Section 12.1.4

Ex12.14

struct destination;
struct connection;

connection connnect(destination*);
void disconnect(connection);
void end_connection(connection *p) { disconnect(*p); }
void f(destination &d)
{
    connection c = connect(&d);
    shared_ptr<connection> p(&c, end_connection);
}

Ex12.15

struct destination;
struct connection;

connection connnect(destination*);
void disconnect(connection);
void end_connection(connection *p) { disconnect(*p); }
void f(destination &d)
{
    connection c = connect(&d);
    shared_ptr<connection> p(&c, [](connection *p) { disconnect(*p); });
}

Exercises Section 12.1.5

Ex12.16

在这里插入图片描述

Ex12.17

int ix = 1024, *pi = &ix, *pi2 = new int(2048);
typedef unique_ptr<int> IntP;

a) IntP p0(ix);		// 非法;类型不匹配
b) IntP p1(pi);		// 合法
c) IntP p2(pi2);	// 合法
d) IntP p3(&ix);	// 合法
e) IntP p4(new int(2048));	// 合法
f) IntP p5(p2.get());	// 合法

Ex12.18

因为可能同时有多个 shared_ptr 指向同一个对象,共享对象所有权故而不需要 release。

Exercises Section 12.3.1

Ex12.27 28

#include<iostream>
#include<fstream>
#include<sstream>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<cstdlib>

using namespace std;

using line_no = vector<string>::size_type;
vector<string> file;    // 文件以每行内容存储
map<string, set<line_no>> wm;   // 单词到行号 set 的映射

string make_pluaral(size_t ctr, const string &word, const string &ending)
{
    return (ctr > 1) ? word + ending : word;
}

string cleanup_str(const string &word)
{
    string ret;
    for (auto it = word.begin(); it != word.end(); ++it)
    {
        if (!ispunct(*it))
            ret += tolower(*it);
    }
    return ret;
}

void input_text(ifstream &is)
{
    string text;
    while (getline(is, text))
    {
        file.push_back(text);       // 保留此行文本
        int n = file.size() - 1;    // 当前行号
        istringstream line(text);   // 将每行分解为每个单词
        string word;
        while (line >> word)
        {
            // 将当前行号插入到其行号 set 中
            // 如果单词不在 wm 中,则添加一项
            wm[cleanup_str(word)].insert(n);
        }
    }
}

ostream &query_and_print(const string &sought, ostream &os)
{
    // 使用 find 而不是下标,避免将该单词添加到容器中
    auto loc = wm.find(sought);
    if (loc == wm.end())    // 未找到
    {
        os << sought << "occurs 0 time" << endl;
    }
    else 
    {
        auto lines = loc->second;   // 行号
        os << sought << "occurs " << lines.size() << " times" << endl;
        for (const auto &num : lines)
            os << "\t(No " << num + 1 << "lines" << *(file.begin() + num) << endl;
    }
    return os;
}

void runQueries(ifstream &infile)
{
    // infile指向我们要查询的文件
    input_text(infile);         // 读入文本并建立查询 map
    while (true)
    {
        cout << "enter word to look for or enter \"q\" to quit: ";
        string s;
        if (!(cin >> s) || s == "q")
            break;
        query_and_print(s, cout) << endl;
    }
}

int main(int argc, char *argv[])
{
    ifstream infile;
    if (argc < 2 || !(infile.open(argv[1], infile)))
    {
        cerr << "No input file !" << endl;
        return EXIT_FAILURE;
    }
    runQueries(infile);
    system("pause");
    return 0;
}

Ex12.29

    do
    {
        cout << "enter word to look for or enter \"q\" to quit: ";
        string s;
        if (!(cin >> s) || s == "q")
            break;
        query_and_print(s, cout) << endl;
    } while (true);

使用 while 比使用 do_while 好

Exercises Section 12.3.2

Ex12.30

class QuertResult;
class TextQuery
{
public:
    using line_no = std::vector<std::string>::size_type;
    TextQuery(std::ifstream &);
    QuertResult query(const std::string &) const;
private:
    std::shared_ptr<std::vector<std::string>> file;
    std::map<std::string, std::shared_ptr<std::set<line_no>>> wm;
};

TextQuery::TextQuery(ifstream &is): file(new vector<string>)
{
    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];
            if (!lines)
                lines.reset(new set<line_no>);
            lines->insert(n);
        }
    }
}

class QuertResult
{
friend std::ostream &print(std::ostream &, const QueryResult &);
public:
    QuertResult(std::string s, std::share_ptr<std::set<line_no>> p, std::shared_ptr<std::vector<std::string>> f) :
        sought(s), lines(p), file(f) { }
private:
    std::string sought;
    std::shared_ptr<std::set<line_no>> lines;
    std::shared_ptr<std::vector<std::string>> file;
};

QueryResult TextQuery::query(const string &sought) const 
{
    static shared_ptr<set<line_no>> nodata(new set<line_no>);
    auto loc = wm.find(sought);
    if (loc == wm.end())
        return QuertResult(sought, nodata, file);
    else
        return QuertResult(sought, loc->second, file);
}

ostream &print(ostream &os, const QuertResult &qr)
{
    os << qr.sought << " occurs " << qr.lines->size() << " "
       << make_pluar(qr.lines->size(), "time", "s") << endl;
    for (auto num : *qr.lines)
        os << "\t(line " << num + 1 << ") " << *(qr.file->begin() + num) << endl;
    return os;
}

Ex12.31

set 会维护关键字的顺序,vector不会;vector 插入元素的效率更高;由于不需要维护关键字的顺序,故而使用 vector 效率更高。

Ex12.32

class StrBlobPtr;
class QueryResult;
class StrBlob 
{
	friend class StrBlobPtr;
public:
	typedef vector<string>::size_type size_type;
	StrBlob();
	StrBlob(initializer_list<string> il);
	bool empty() const { return data->empty(); }
	size_type size() const { return data->size(); }
	void push_back(const string &s) { data->push_back(s); }
	void pop_back();
	string& front();
	const string& front() const;
	string& back();
	const string& back() const;
	StrBlobPtr begin();
	StrBlobPtr end();
private:
	shared_ptr<vector<string>> data;
	void check(size_type i, const string &msg) const;
};
 
class StrBlobPtr 
{
	friend bool eq(const StrBlobPtr &lhs, const StrBlobPtr &rhs);
public:
	StrBlobPtr(): curr(0) { }
	StrBlobPtr(StrBlob &a, size_t sz = 0):
		wptr(a.data), curr(sz) { }
	string& deref() const;
	StrBlobPtr& incr();
private:
	shared_ptr<vector<string>> check(size_t, const string&) const;
	weak_ptr<vector<string>> wptr;
	size_t curr;
};
 
void StrBlob::check(size_type i, const string &msg) const 
{
	if (data->size() <= i)
		throw out_of_range(msg);
}
 
StrBlob::StrBlob(): data(make_shared<vector<string>>()) { }
 
StrBlob::StrBlob(initializer_list<string> il): data(make_shared<vector<string>>(il)) { }
 
void StrBlob::pop_back()
{
	check(0, "pop back on empty StrBlob");
	data->pop_back();
}
 
string &StrBlob::front()
{
	check(0, "front on empty StrBlob");
	return data->front();
}
 
const string &StrBlob::front() const
{
	check(0, "front on empty StrBlob");
	return data->front();
}
 
string &StrBlob::back()
{
	check(0, "back on empty StrBlob");
	return data->back();
}
 
const string &StrBlob::back() const
{
	check(0, "back on empty StrBlob");
	return data->back();
}
 
StrBlobPtr StrBlob::begin() 
{
	return StrBlobPtr(*this); 
}
 
StrBlobPtr StrBlob::end() 
{
	auto ret = StrBlobPtr(*this, data->size());
	return ret;
}
 
shared_ptr<vector<string>> StrBlobPtr::check(size_t i, const string &msg) const
{
	auto ret = wptr.lock();
	if (!ret)
		throw runtime_error("unbound StrBlobPtr");
	if ( i >= ret->size() )
		throw out_of_range(msg);
	return ret;
}
 
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;
}
 
inline bool eq(const StrBlobPtr &lhs, const StrBlobPtr &rhs)
{
	shared_ptr<vector<string>> l = lhs.wptr.lock(), r = rhs.wptr.lock();
	
	if (l == r)
		return (!r || lhs.curr == rhs.curr);
	else 
		return false;
}
 
inline bool neq(const StrBlobPtr &lhs, const StrBlobPtr &rhs)
{
	return !eq(lhs, rhs);
}

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;
};
 
TextQuery::TextQuery(ifstream &infile): file(make_shared<StrBlob>())
{
	string line;
	string word;
	line_no index = 0;
	
	while (getline(infile, line)) {
		file->push_back(line);
		++index;
		istringstream strline(line);
		while (strline >> word) {
			/* 消除词首和词尾的标点 */
			if (ispunct(word[0]))
				word.erase(0, 1);
			if (ispunct(word[word.size()-1]))
				word.pop_back();
			if (ispunct(word[word.size()-1]))
				word.pop_back();
			
			if (!wm[word])
				wm[word] = make_shared<set<line_no>>();
			wm[word]->insert(index);
		}
	}
}
 
QueryResult TextQuery::query(const string &s) const
{
	static shared_ptr<set<line_no>> nodata(make_shared<set<line_no>>());
	
	auto loc = wm.find(s);
	if (loc == wm.end())
		return QueryResult(s, nodata, file);
	else
		return QueryResult(s, loc->second, file);
}

Ex12.33

// 添加如下成员函数
set<line_no>::const_iterator begin() const { return lines->begin(); }
set<line_no>::const_iterator end() const { return lines->end(); }
shared_ptr<StrBlob> get_file() { return file; }
posted @   astralcon  阅读(46)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
点击右上角即可分享
微信分享提示