C++ Primer第五版_第十二章习题答案(11~20)

文章目录

      • 练习12.11
      • 练习12.12
      • 练习12.13
      • 练习12.14
      • 练习12.15
      • 练习12.16
      • 练习12.17
      • 练习12.18
      • 练习12.19
      • 练习12.20

练习12.11

如果我们像下面这样调用 process,会发生什么?

process(shared_ptr(p.get()));

这样会创建一个新的智能指针,它的引用计数为 1,这个智能指针所指向的空间与 p 相同。在表达式结束后,这个临时智能指针会被销毁,引用计数为 0,所指向的内存空间也会被释放。而导致 p 所指向的空间被释放,使得 p 成为一个空悬指针。

练习12.12

p 和 sp 的定义如下,对于接下来的对 process 的每个调用,如果合法,解释它做了什么,如果不合法,解释错误原因:

auto p = new int();
auto sp = make_shared();
(a) process(sp);
(b) process(new int());
(c) process(p);
(d) process(shared_ptr(p));
  • (a) 合法。将sp 拷贝给 process函数的形参,在函数里面引用计数为 2,函数结束后引用计数为 1。
  • (b) 不合法。不能从内置指针隐式转换为智能指针。
  • © 不合法。不能从内置指针隐式转换为智能指针。
  • (d) 合法。但是智能指针和内置指针一起使用可能会出现问题,在表达式结束后智能指针会被销毁,它所指向的对象也被释放。而此时内置指针 p 依旧指向该内存空间。之后对内置指针 p 的操作可能会引发错误。

练习12.13

如果执行下面的代码,会发生什么?

auto sp = make_shared();
auto p = sp.get();
delete p;

智能指针 sp 所指向空间已经被释放,再对 sp 进行操作会出现错误。

练习12.14

编写你自己版本的用 shared_ptr 管理 connection 的函数。

#include 
#include 
#include 

struct connection
{
	std::string ip;
	int port;
	connection(std::string i, int p) : ip(i), port(p) {}
};

struct destination
{
	std::string ip;
	int port;
	destination(std::string i, int p) : ip(i), port(p) {}
};

connection connect(destination* pDest)
{
	std::shared_ptr 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 p(&conn, end_connection);
	std::cout << "connecting now(" << p.use_count() << ")" << std::endl;
}

int main()
{
	destination dest("220.181.111.111", 10086);
	f(dest);

	return 0;
}

练习12.15

重写第一题的程序,用 lambda 代替end_connection 函数。

#include 
#include 
#include 

struct connection
{
	std::string ip;
	int port;
	connection(std::string i, int p) : ip(i), port(p) {}
};

struct destination
{
	std::string ip;
	int port;
	destination(std::string i, int p) : ip(i), port(p) {}
};

connection connect(destination* pDest)
{
	std::shared_ptr 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 p(&conn, [] (connection* p){ disconnect(*p); });
	std::cout << "connecting now(" << p.use_count() << ")" << std::endl;
}

int main()
{
	destination dest("220.181.111.111", 10086);
	f(dest);

	return 0;
}

练习12.16

如果你试图拷贝或赋值 unique_ptr,编译器并不总是能给出易于理解的错误信息。编写包含这种错误的程序,观察编译器如何诊断这种错误。

#include 
#include 
#include 

int main()
{
	std::unique_ptr p1(new std::string("hello"));
	//std::unique_ptr p2 = p1; ³¢ÊÔÒýÓÃÒÑɾ³ýµÄº¯Êý

	std::cout << *p1 << std::endl;
	p1.reset(nullptr);
	return 0;
}

尝试引用已删除的函数

练习12.17

下面的 unique_ptr 声明中,哪些是合法的,哪些可能导致后续的程序错误?解释每个错误的问题在哪里。

int ix = 1024, *pi = &ix, *pi2 = new int(2048);
typedef unique_ptr 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());
  • (a) 不合法。在定义一个 unique_ptr 时,需要将其绑定到一个new 返回的指针上。
  • (b) 合法。但是可能会有后续的程序错误。当 p1 被释放时,p1 所指向的对象也被释放,所以导致 pi 成为一个空悬指针。
  • © 合法。但是也可能会使得 pi2 成为空悬指针。
  • (d) 不合法。当 p3 被销毁时,它试图释放一个栈空间的对象。
  • (e) 合法。
  • (f) 不合法。p5 和 p2 指向同一个对象,当 p5 和 p2 被销毁时,会使得同一个指针被释放两次。

练习12.18

shared_ptr 为什么没有 release 成员?

release 成员的作用是放弃控制权并返回指针,因为在某一时刻只能有一个 unique_ptr 指向某个对象,unique_ptr 不能被赋值,所以要使用 release 成员将一个 unique_ptr 的指针的所有权传递给另一个 unique_ptr。而 shared_ptr 允许有多个 shared_ptr 指向同一个对象,因此不需要 release 成员。

练习12.19

定义你自己版本的 StrBlobPtr,更新 StrBlob 类,加入恰当的 friend 声明以及 begin 和 end 成员。

#ifndef EX12_19_H
#define EX12_19_H

#include 
#include 
#include 
#include 
#include 

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

class StrBlobPtr;

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

	StrBlobPtr begin();
	StrBlobPtr end();

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

	size_type size() const { return data->size(); }
	bool empty() const { return data->empty(); }

	void push_back(const string& s) { data->push_back(s); }
	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> 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, "increment past end of StrBlobPtr");
		++curr;
		return *this;
	}

private:
	std::shared_ptr> 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> wptr;
	size_t curr;
};

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

练习12.20

编写程序,逐行读入一个输入文件,将内容存入一个 StrBlob 中,用一个 StrBlobPtr 打印出 StrBlob 中的每个元素。

#include 
#include 
#include "exercise12_19.h"

using namespace std;

int main()
{
	ifstream ifs("./data/books.txt");
	StrBlob sb;
	string s;
	while (getline(ifs, s))
	{
		sb.push_back(s);
	}
	for (StrBlobPtr sbp = sb.begin(); sbp != sb.end(); sbp.incr())
	{
		cout << sbp.deref() << endl;
	}

	return 0;
}

你可能感兴趣的:(C++《i+1》,c++,开发语言,算法)