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

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

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<int>(p.get()));

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

练习12.12

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

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

练习12.13

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

auto sp = make_shared<int>();
auto p = sp.get();
delete p;

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

练习12.14

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

#include <iostream>
#include <memory>
#include <string>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<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 << "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 <iostream>
#include <memory>
#include <string>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<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* 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 <iostream>
#include <string>
#include <memory>int main()
{std::unique_ptr<std::string> p1(new std::string("hello"));//std::unique_ptr<std::string> 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<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());
  • (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 <string>
#include <vector>
#include <initializer_list>
#include <memory>
#include <stdexcept>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& 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<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, "increment 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;
};StrBlobPtr StrBlob::begin()
{return StrBlobPtr(*this);
}
StrBlobPtr StrBlob::end()
{return StrBlobPtr(*this, data->size());
}
#endif

练习12.20

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

#include <iostream>
#include <fstream>
#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;
}