练习12.1
在此代码的结尾,b1 和 b2 各包含多少个元素?
StrBlob b1;
{
StrBlob b2 = {
"a", "an", "the"};
b1 = b2;
b2.push_back("about");
}
b1包含4个元素;
b2被销毁。
练习12.2
编写你自己的StrBlob 类,包含const 版本的 front 和 back。
strblob.h
#ifndef STRBLOB_H_
#define STRBLOB_H_
#include <string>
#include <initializer_list>
#include <memory>
#include <vector>
#include <stdexcept>
class StrBlob
{
public:
typedef std::vector<std::string>::size_type size_type;
StrBlob();
StrBlob(std::initializer_list<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();
std::string& back();
const std::string& front() const;
const 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 StrBlob");
return data->front();
}
std::string & StrBlob::back()
{
check(0, "back on empty StrBlob");
return data->back();
}
const std::string& StrBlob::front() const
{
check(0, "front on empty StrBlob");
return data->front();
}
const std::string& StrBlob::back() const
{
check(0, "back on empty StrBlob");
return data->back();
}
void StrBlob::pop_back()
{
check(0, "pop_back on empty StrBlob");
data->pop_back();
}
#endif
ex02.cpp
#include "StrBlob.h"
#include <iostream>
int main()
{
StrBlob b1 = {
"a", "an", "the"};
const StrBlob b2 = {
"a", "b", "c"};
std::cout << b1.back() << std::endl;
std::cout << b2.back() << std::endl;
return 0;
}
练习12.3
StrBlob 需要const 版本的push_back 和 pop_back吗?如需要,添加进去。否则,解释为什么不需要。
不需要,添加进去虽然编译器不会报错,但是这样不符合类使用者的使用习惯。
练习12.4
在我们的 check 函数中,没有检查 i 是否大于0。为什么可以忽略这个检查?
可以忽略,本身i就是大于0的。
练习12.5
我们未编写接受一个 initializer_list explicit 参数的构造函数。讨论这个设计策略的优点和缺点。
使用explicit之后
优点:我们可以清楚地知道使用的是哪种类型;
缺点:不易使用,需要显示地初始化。
练习12.6
编写函数,返回一个动态分配的 int 的vector。将此vector 传递给另一个函数,这个函数读取标准输入,将读入的值保存在 vector 元素中。再将vector传递给另一个函数,打印读入的值。记得在恰当的时刻delete vector。
#include <string>
#include <iostream>
#include <vector>
std::vector<int> *create_vi()
{
return new std::vector<int>;
}
void push_vi(std::vector<int> *p)
{
int i;
while(std::cin >> i)
p->push_back(i);
}
void print_vi(std::vector<int> *p)
{
for(const auto i : (*p))
std::cout << i << std::endl;
}
int main()
{
auto p = create_vi();
push_vi(p);
print_vi(p);
delete p;
return 0;
}
练习12.7
重做上一题,这次使用 shared_ptr 而不是内置指针。
#include <string>
#include <iostream>
#include <vector>
#include <memory>
std::shared_ptr<std::vector<int>> create_vi()
{
return std::make_shared<std::vector<int>>();
}
void push_vi(std::shared_ptr<std::vector<int>> p)
{
int i;
while(std::cin >> i)
p->push_back(i);
}
void print_vi(std::shared_ptr<std::vector<int>> p)
{
for(const auto i : (*p))
std::cout << i << std::endl;
}
int main()
{
auto p = create_vi();
push_vi(p);
print_vi(p);
// delete p;
return 0;
}
练习12.8
下面的函数是否有错误?如果有,解释错误原因。
bool b() {
int* p = new int;
// ...
return p;
}
指针p被转换成bool值,new的内存没有被delete,内存没有被释放。
练习12.9
解释下面代码执行的结果。
int *q = new int(42), *r = new int(100);
r = q;
auto q2 = make_shared<int>(42), r2 = make_shared<int>(100);
r2 = q2;
r=q后r所指的内存没有释放,应该先delete r,再r=q;
第二段代码内存会自动释放。
练习12.10
下面的代码调用了第413页中定义的process 函数,解释此调用是否正确。如果不正确,应如何修改?
shared_ptr<int> p(new int(42));
process(shared_ptr<int>(p));
正确。
练习12.11
如果我们像下面这样调用 process,会发生什么?
process(shared_ptr<int>(p.get()));
离开process时,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)合法,将智能指针赋值给process;
(b)不合法,shared_ptr初始化内置指针时需要使用直接初始化的形式;
(c)不合法,shared_ptr初始化内置指针时需要使用直接初始化的形式;
(d)合法。
练习12.13
如果执行下面的代码,会发生什么?
auto sp = make_shared<int>();
auto p = sp.get();
delete p;
sp和p指向的是同一个对象,程序中手动销毁了p所指向的对象,程序结束会自动销毁sp所指向的对象,会销毁两次同一个对象而报错。报错代码如下:
$ ./ex13
double free or corruption (out)
Aborted (core dumped)
练习12.14
编写你自己版本的用 shared_ptr 管理 connection 的函数。
#include <string>
#include <memory>
#include <iostream>
struct destination
{
std::string des;
destination(std::string des_) : des(des_){
}
};
struct connection
{
std::string conn;
connection(std::string conn_) : conn(conn_){
}
};
connection connect(destination *des_)
{
std::cout << "connect to " << des_->des << std::endl;
return connection (des_->des);
}
void disconnect(connection conn_)
{
std::cout << "disconnect " << conn_.conn << std::endl;
}
void end_connection(connection *p){
disconnect(*p); }
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 des("aaa");
f(des);
return 0;
}
练习12.15
重写第一题的程序,用 lambda 代替end_connection 函数。
#include <string>
#include <memory>
#include <iostream>
struct destination
{
std::string des;
destination(std::string des_) : des(des_){
}
};
struc