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参数版本)。


0 0
原创粉丝点击