C++ Prime 0x0C 练习题解
Posted 鱼竿钓鱼干
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++ Prime 0x0C 练习题解相关的知识,希望对你有一定的参考价值。
📔 C++ Prime 0x0C 练习题解
推荐阅读 《C++ Primer 5th》知识点总结&练习题解
12.1 动态内存与智能指针
12.1.1 shared_ptr 类
12.1 在此代码的结尾,
b1
和b2
各包含多少个元素?StrBlob b1; StrBlob b2 = "a", "an", "the"; b1 = b2;//b1,b2共享相同的元素 b2.push_back("about");//b1,b2都有4个元素 //b2被析构了,但是不影响b1
如果两个对象共享底层数据,当某个对象被销毁是,我们不能单方面地销毁底层数据
12.2 编写你自己的
StrBlob
类,包含const
版本的front
和back
。
#include <stdexcept>
#include <string>
#include <vector>
#include <iostream>
#include <initializer_list>
#include <memory>
#include <exception>
class StrBlob
public:
typedef std::vector<std::string>::size_type size_type;
StrBlob();
StrBlob(std::initializer_list<std::string> il);
size_type size()constreturn data->size();
bool empty()constreturn data->empty();
void push_back(const std::string &t)data->push_back(t);
void pop_back();
std::string& front();
std::string& front()const;
std::string& back();
std::string& back()const;
private:
std::shared_ptr<std::vector<std::string>>data;
void check(size_type i,const std::string &msg)const;
;
StrBlob::StrBlob():data(std::make_shared<std::vector<std::string>>())
StrBlob::StrBlob(std::initializer_list<std::string> il)
:data(std::make_shared<std::vector<std::string>>(il))
void StrBlob::check(size_type i,const std::string &msg)const
if(i >= data->size())
throw std::out_of_range(msg);
std::string& StrBlob::front()
check(0,"front on empty StrBlod");
return data->front();
std::string& StrBlob::front()const
check(0,"front on empty StrBlod");
return data->front();
std::string& StrBlob::back()
check(0,"back on empty StrBlod");
return data->back();
std::string& StrBlob::back()const
check(0,"back on empty StrBlod");
return data->back();
void StrBlob::pop_back()
check(0,"pop_back on empty StrBlod");
data->pop_back();
int main()
const StrBlob a"this","is","a","const","StrBlob";
StrBlob b"this","is","not","a","const","StrBlob";
std::cout << a.front() << " " << a.back() << std::endl;
std::cout << b.front() << " " << b.back() << std::endl;
return 0;
12.3 StrBlob 需要const 版本的push_back 和 pop_back吗?如需要,添加进去。否则,解释为什么不需要。
不需要,push_back
和pop_back
会改变对象内容
12.4 在我们的
check
函数中,没有检查i
是否大于0。为什么可以忽略这个检查?
size_type
是无符号整型,传负数会变成正数
12.5 我们未编写接受一个
initializer_list explicit
参数的构造函数。讨论这个设计策略的优点和缺点。
优点:不使用explicit
则initializer_list
可以隐式转换为StrBlob
,这个逻辑上是可行的
缺点:如果我们确实需要用initializer_list
,那么编译器会自动转为StrBlod
12.1.2 直接管理内存
12.6 编写函数,返回一个动态分配的
int
的vector
。将此vector
传递给另一个函数,这个函数读取标准输入,将读入的值保存在vector
元素中。再将vector
传递给另一个函数,打印读入的值。记得在恰当的时刻delete vector
。
#include <vector>
#include <iostream>
#include <memory>
std::vector<int>* alloc_vector()
return new std::vector<int>();
void read_vector(std::vector<int>* p)
for(int x;std::cin >> x;)
p->push_back(x);
void print_vector(const std::vector<int>* p)
for(auto i:*p)std::cout << i << std::endl;
int main()
auto p = alloc_vector();
read_vector(p);
print_vector(p);
delete p;
return 0;
12.7 重做上一题,这次使用
shared_ptr
而不是内置指针。
#include <vector>
#include <iostream>
#include <memory>
using T = std::vector<int>;
std::shared_ptr<T> alloc_vector()
return std::make_shared<T>();
void read_vector(std::shared_ptr<T> p)
for(int x;std::cin >> x;)
p->push_back(x);
void print_vector(const std::shared_ptr<T> p)
for(auto i:*p)std::cout << i << std::endl;
int main()
auto p = alloc_vector();
read_vector(p);
print_vector(p);
return 0;
12.8 下面的函数是否有错误?如果有,解释错误原因。
bool b()
int* p = new int;
// ...
return p;//被强制转为 bool 没有释放 p 指向的对象
12.9 解释下面代码执行的结果。
int *q = new int(42), *r = new int(100);//q 指向 42,r 指向100
r = q;//r q 都指向 42,r 指向 100的内存空间没有释放,内存泄漏
auto q2 = make_shared<int>(42), r2 = make_shared<int>(100);
r2 = q2;//r2,q2都指向42, 100的内存空间不被r2引用的时候自动释放
12.1.3 shared_ptr 和 new 结合使用
12.10 下面的代码调用了第413页中定义的
process
函数,解释此调用是否正确。如果不正确,应如何修改?
shared_ptr<int> p(new int(42));
process(shared_ptr<int>(p));
正确,传入的shared_ptr<int>(p)
创建一个临时对象,和p
引用同一个对象,引用计数为2
函数结束,临时的智能指针被销毁,此时引用计数为1
12.11 如果我们像下面这样调用
process
,会发生什么?
process(shared_ptr<int>(p.get()));
p.get()
返回一个内置指针
shared_ptr<int>(p.get())
创建一个新的智能指针对象,传入的时候引用计数为1,传出的时候引用计数为0,指向的内存被释放,此时p
变成了空悬指针
12.12
p
和sp
的定义如下,对于接下来的对process
的每个调用,如果合法,解释它做了什么,如果不合法,解释错误原因:
auto p = new int();
auto sp = make_shared<int>();
(a) process(sp);//合法,传入的时候引用计数为2,结束的时候引用计数为1
(b) process(new int());//不合法,内置指针不能隐式转为智能指针
(c) process(p);//不合法,内置指针不能隐式转为智能指针
(d) process(shared_ptr<int>(p));//对于这个函数而言可以,但是会造成p成为空悬指针
12.13 如果执行下面的代码,会发生什么?
auto sp = make_shared<int>();
auto p = sp.get();
delete p;
sp
指向的内存空间已经被释放,再用sp
操作会出错
12.1.4 智能指针和异常
12.14 编写你自己版本的用
shared_ptr
管理connection
的函数。
#include <vector>
#include <iostream>
#include <memory>
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 c = connect(&d);
std::shared_ptr<connection>p(&c,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 <vector>
#include <iostream>
#include <memory>
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 c = connect(&d);
std::shared_ptr<connection>p(&c,[](connection* pConn)disconnect(*pConn););
std::cout << "connecting now(" << p.use_count() << ")" << std::endl;
int main()
destination dest("220.181.111.111",10086);
f(dest);
return 0;
12.1.5 unique_ptr
12.16 如果你试图拷贝或赋值
unique_ptr
,编译器并不总是能给出易于理解的错误信息。编写包含这种错误的程序,观察编译器如何诊断这种错误。
#include <string>
#include <vector>
#include <iostream>
#include <memory>
int main()
std::unique_ptr<std::string>p(new std::string("abc"));
// std::unique_ptr<std::string>q(p);//拷贝
// unique_ptr' has been explicitly marked deleted here unique_ptr(const unique_ptr&) = delete;
std::unique_ptr<std::string>r;
//r = p;//赋值
//candidate function not viable: no known conversion from 'std::unique_ptr<std::string>' (aka 'unique_ptr<basic_string<char>>') to 'std::nullptr_t' (aka 'nullptr_t') for 1st argumentoperator=(nullptr_t) noexcept
return 0;
12.17 下面的
unique_ptr
声明中,哪些是合法的,哪些可能导致后续的程序错误?解释每个错误的问题在哪里。
int ix = 1024, *pi = &ix, *pi2 = new int(2048);
typedef unique_ptr<int> IntP;
(a) IntP p0(ix);//不合法,当我们在定义一个 unique_ptr 时,需要将其绑定到一个new 返回的指针上。
(b) IntP p1(pi);//不合法,当我们在定义一个 unique_ptr 时,需要将其绑定到一个new 返回的指针上。
(c) IntP p2(pi2);//合法,但pi2可能会变成空悬指针
(d) IntP p3(&ix);//不合法,当 p3 被销毁时,它试图释放一个栈空间的对象。
(e) IntP p4(new int(2048));//合法
(f) IntP p5(p2.get());//不合法,p5 和 p2 指向同一个对象,但是他们互相独立,p5被销毁的时候也释放了p2指向的对象,p2变成空悬
12.18
shared_ptr
为什么没有release
成员?
release
放弃对指针的控制权,返回指针
unique_ptr
一个对象只能被一个指针控制,需要释放控制权来给其他指针
shared_ptr
允许多个指针指向同一个对象,不需要转移控制权
12.1.6 weak_ptr
12.19 定义你自己版本的
StrBlobPtr
,更新StrBlob
类,加入恰当的friend
声明以及begin
和end
成员。12.20 编写程序,逐行读入一个输入文件,将内容存入一个
StrBlob
中,用一个StrBlobPtr
打印出StrBlob
中的每个元素。
#include <cstddef>
#include <stdexcept>
#include <string>
#include <vector>
#include <iostream>
#include <initializer_list>
#include <memory>
#include <exception>
#include <fstream>
class StrBlobPtr;
class StrBlob以上是关于C++ Prime 0x0C 练习题解的主要内容,如果未能解决你的问题,请参考以下文章