12.1节练习
来源:互联网 发布:java 是干嘛的 编辑:程序博客网 时间:2024/06/05 15:38
练习12.1 在此代码的结尾,b1和b2各包含多少个元素?
StrBlob b1{
StrBlob b2 = { "a","an","the" };
b1 = b2;
b2.push_back( "about" );
}
b1和b2共享数据,b1和b2均包含4个元素。
练习12.2 编写你自己的StrBlob类,包含const版本的front和back。
#include <string>#include <vector>#include <memory>#include <stdexcept>class StrBlob {public:typedef std::vector<std::string>::size_type size_type;StrBlob():data(std::make_shared<std::vector<std::string>>()){}StrBlob(std::initializer_list<std::string> il):data(std::make_shared<std::vector<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() { front_check(); return data->front(); }std::string& back() { back_check(); return data->back(); }const std::string& front() const { front_check(); return data->front(); }const std::string& back() const { back_check(); return data->back(); }private:std::shared_ptr<std::vector<std::string>> data;void check(size_type i, const std::string &msg) const;void front_check();void back_check();};void StrBlob::check(StrBlob::size_type i, const std::string &msg) const{if (i >= data->size()) {throw std::out_of_range(msg);}}void StrBlob::pop_back(){check(0, "pop_back on empty StrBlob");data->pop_back();}void StrBlob::front_check()const{StrBlob::check(0,"front on empty StrBlob");}void StrBlob::back_check()const{StrBlob::check(0, "back on empty StrBlob");}
练习12.3 StrBlob需要const版本的push_back和pop_back吗?如果需要,添加进去,否则,解释为什么不需要。
不需要。
常量成员函数不改变对象的数据。而push_back和pop_back改变容器的元素。
练习12.4 在我们的check函数中,没有检验i是否大于0.为什么可以忽略这个检查?
size_type是类型是vector<T>::size_type 不会小于0;
练习12.5 我们未编写接受一个initializer_list explict参数的构造函数,讨论这个设计的策略的优点和缺点。
优点:explict构造函数只能用于直接初始化,不能用于拷贝初始化。
缺点:可能在意想不到的情况下使用了隐式转化。
练习12.6 编写函数,返回一个动态分配的Int的vector将此vector传递给另一个函数,这个函数读取标准输入,将读入的值保存在vector元素中。再将vector传递给另一个函数,打印读入的值。记得在恰当的时刻delete vector。
#include <iostream>#include <new>#include <vector>using namespace std;vector<int>* func_1();void func_2(vector<int>*);void func_3(vector<int>*);int main(){auto p_vec = func_1();func_2(p_vec);func_3(p_vec);}// 生成指向vector<int>的动态指针vector<int>* func_1(){vector<int> *p = new vector<int>;return p;}// 输入数据void func_2(vector<int>* p){int val;while (cin >> val){p->push_back(val);}}// 输出数据,并释放内存void func_3(vector<int>* p){for (auto &c : *p){cout << c << " ";}delete p;cout << endl;}
练习12.7 重做上一题,这次使用shared_ptr而不是内置指针。
#include <iostream>#include <vector>#include <memory>using namespace std;// 返回类型为智能指针shared_ptr<vector<int>> func_1();void func_2(shared_ptr<vector<int>>);void func_3(shared_ptr<vector<int>>);int main(){auto p_vec = func_1();func_2(p_vec);func_3(p_vec);}shared_ptr<vector<int>> func_1(){auto it = make_shared<vector<int>>();return it;}void func_2(shared_ptr<vector<int>> p){int val;while (cin >> val){p->push_back(val);}}void func_3(shared_ptr<vector<int>> p){for (auto &c : *p){cout << c << " ";}cout << endl;}
练习12.8 下面的函数是否有错误? 如果有,解释错误原因。
bool b()
{
int * p = new int;
return p;
}
错误。p是指向int的指针,返回类型是bool类型,不匹配。
练习12.9 解释下面代码执行的结果:
int *q = new int (42), *r = new int (100);
r = q; // 指针r和q指向同一个对象42
auto q2 = make_shared<int> (42), r2 = make_shared<int>(100);
r2 = q2; // 指针r2和q2指向同一个对象42,同时q2对象被删除,内存被释放
练习12.10 下面的代码调用了第413页中定义的process函数,解释此调用是否正确。如果不正确,应该如何修改?
shared_ptr<int> p (new int (42));
process(shared_ptr <int>(p));
正确。 实参创建一个临时的shared_ptr指向42,process中引用计数值为2。
练习12.11 如果我们像下面这样调用process,会发生什么?
process (shared_ptr<int>(p.get()) );
产生未定义的行为:ptr和p两个独立的shared_ptr指向相同的内存。当process结束ptr释放内存,p成为空悬指针。
将另一智能指针也绑到get返回的指针上,这一做法是错误的。
练习12.12 p和sp的定义如下,对于接下来的process的每个调用,如果合法,解释它做了什么,如果不合法,解释错误原因:
auto p = new int();auto sp = make_shared<int>();(a) process(sp); //合法,在process中引用计算值为2(b) process(new int ()); //非法,不能将一个内置指针转化成智能指针(c) process(p); //非法,同上(d) process(shared_ptr<int>(p)); //合法,但内存会被释放
练习12.13 如果执行下面的代码,会发生什么?
auto sp = make_shared<int>();auto p = sp.get();delete p;p和sp是指向相同的内存,但他们是相互独立创建的,因此各自的引用计数都是1。当delete p后所指的内存被释放,sp成为空悬指针。
使用get返回的指针不能delete此指针。
练习12.14 编写你自己版本的用shared_ptr管理connection的函数。
#include <iostream>#include <memory>#include <string>using namespace std;struct destination {};struct connection {};connection connect(destination *);void disconnection(connection);void f(destination &);void end_connection(connection *p) { disconnection(*p); }int main(){destination des_item;f(des_item);return 0;}void f(destination &d){connection c = connect(&d);//shared_ptr<connection> p(&c, end_connection);shared_ptr<connection> p2(&c, [] (connection *p2){disconnection(*p2); });}connection connect(destination *p){connection item;cout << "here is connect function" << endl;return item;}void disconnection(connection){cout << "bey bye" << endl;}
练习12.15 编写你自己版本的用shared_ptr管理connection函数。
shared_ptr<connection> p2(&c, [] (connection *p2){disconnection(*p2); });
练习12.16 如果你试图拷贝或赋值unique_ptr,编译器并不总是能给出易于理解的错误信息。编写包含这种错误的程序,观察编译器如何诊断这种错误。
严重性 代码 说明 项目 文件 行 禁止显示状态
错误 C2280 “std::unique_ptr<int,std::default_delete<_Ty>>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)”: 尝试引用已删除的函数 Cpprimer c:\users\pierce\documents\visual studio 2015\projects\cpprimer\12.16.cpp 7
。。。
练习12.17 下面的unique_ptr声明中,哪些是合法的,哪些是可能导致后续的程序错误?解释每个错误的问题在哪里?
Intp p0(ix); //非法,ix不是指针Intp p1(pi);//非法,定义unique_ptr时,须将其绑定到一个new返回的指针上Intp p2(pi2);//合法Intp p3(&ix); //非法,同p1Intp p4(new int(2048)); //合法Intp p5(p2.get()); //非法,p2.get()返回的是内置指针,同p1
练习12.18 shared_ptr为什么没有release成员?
release成员的作用是放弃指针对对象的管理,不操作对象内存。
shared_ptr类型内置的引用计数在不为0的情况下能够实现上述的功能。
练习12.19 定义你自己版本的StrBlobPtr,更新StrBlob类,加入恰当的friend声明以及end成员。
//写入begin和end成员函数程序报错。
//StrBlobPtr类在StrBlob中是未定义的不完全类
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:std::shared_ptr<std::vector<std::string>> check(std::size_t, const std::string&) const;std::weak_ptr<std::vector<std::string>> wptr;std::size_t curr;};std::shared_ptr<std::vector<std::string>> StrBlobPtr::check(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;}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;}
练习12.20 编写程序,逐行读入一个文件,将内容存入一个StrBlob中,用一个StrBlobPtr打印出StrBlob中的每个元素。
#include <iostream>#include <fstream>#include <string>#include "StrBlob.h"using namespace std;int main(){ifstream text("map_file.txt");string line;StrBlob item;while (getline(text, line)) {item.push_back(line);}StrBlobPtr p(item, 0);size_t i = 0;for (auto iter = item.size(); i < iter; ++i,p.incr()) {cout << p.deref() << endl;}}
练习 12.21 也可以这样编写StrBlobPtr的deref成员:
std::string& deref() const{return (*check(curr, "dereference past end")[curr]);}你认为哪个版本更好?为什么?
先前版本更好。 可读性更高。
练习12.22 为了能让StrBlobPtr使用const StrBlob,你觉得应该如何修改?定义一个名为constStrBlobPtr类,使其能够指向const StrBlobPtr。
StrBlobPtr(const StrBlob &a, size_t = 0) :wptr(a.data), curr(sz) {}重载构造函数的(const参数版本)。
- 12.1节练习
- 第十二章 12.1.4节练习 & 12.1.5节练习
- 第十二章 12.1.1节练习
- 第十二章 12.1.2节练习
- 第十二章 12.1.3节练习
- 第十二章 12.1.6节练习
- C++ Primer 练习答案 1.2节练习
- C++ Primer 练习答案 1.4节练习
- 第一章 1.1节练习
- 第一章 1.2节练习
- 第一章 1.3节练习
- 10.1节练习
- 10.2.1节练习
- 10.2.2节练习
- 10.2.3节练习
- 10.3.1节练习
- 10.3.2 节练习
- 10.3.3节练习
- mysql优化
- 航电 Problem 2044一直小蜜蜂
- Valid Number
- Hypermesh Notes 2
- 关于内存问题提醒!结构体+protobuf做协议体发送!
- 12.1节练习
- NSURLSession(一)GET请求
- jtable导出到excel
- shell 基础 $(cd `dirname $0`;pwd)
- MySQL性能优化的最佳20+条经验
- Android Service
- Solr入门之官方文档6.0阅读笔记系列(四)
- NSURLSession(二)POST请求
- IOS中延时执行的几种方式的比较和汇总