C++ Primer第五版_第十二章习题答案(1~10)
文章目录
-
-
- 练习12.1
- 练习12.2
-
- 头文件
- 函数
- 练习12.3
- 练习12.4
- 练习12.5
- 练习12.6
- 练习12.7
- 练习12.8
- 练习12.9
- 练习12.10
-
练习12.1
在此代码的结尾,b1 和 b2 各包含多少个元素?
StrBlob b1;
{StrBlob b2 = {"a", "an", "the"};b1 = b2;b2.push_back("about");
}
它们实际操作的是同一个vector,都包含4个元素。在代码的结尾,b2 被析构了,不影响 b1 的元素。
练习12.2
编写你自己的StrBlob 类,包含const 版本的 front 和 back。
头文件
#include <vector>
#include <memory>
#include <string>
#include <initializer_list>
#include <exception>using std::vector; using std::string;class StrBlob
{
public:using size_type = vector<string>::size_type;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) const{data->push_back(s);}void pop_back() const{check(0, "pop_back on empty StrBlob");data->pop_back();}string& front(){check(0, "front on empty StrBlob");return data->front();}string& back(){check(0, "back on empty StrBlob");return data->back();}const string& front() const{check(0, "front on empty StrBlob");return data->front();}const 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;
};
函数
#include <iostream>
#include "exercise12_2.h"int main()
{StrBlob sb{ "hello", "world" };const StrBlob csb{ "const", "hello", "world", "aaa" };std::cout << "sb : " << sb.front() << " " << sb.back() << std::endl;std::cout << "csb : " << csb.front() << " " << csb.back() << std::endl;return 0;
}
练习12.3
StrBlob 需要const 版本的push_back 和 pop_back吗?如需要,添加进去。否则,解释为什么不需要。
不需要。push_back
和 pop_back
会改变对象的内容。而 const 对象是只读的,因此不需要。
练习12.4
在我们的 check 函数中,没有检查 i 是否大于0。为什么可以忽略这个检查?
因为 size_type 是一个无符号整型,当传递给 check 的参数小于 0 的时候,参数值会转换成一个正整数。
练习12.5
我们未编写接受一个 initializer_list explicit 参数的构造函数。讨论这个设计策略的优点和缺点。
构造函数不是 explicit 的,意味着可以从 initializer_list 隐式转换为 StrBlob。在 StrBlob 对象中,只有一个数据成员 data,而 StrBlob 对象本身的含义,也是一个管理字符串的序列。因此,从 initializer_list 到 StrBlob 的转换,在逻辑上是可行的。而这个设计策略的缺点,可能在某些地方我们确实需要 initializer_list,而编译器仍会将之转换为 StrBlob。
练习12.6
编写函数,返回一个动态分配的 int 的vector。将此vector 传递给另一个函数,这个函数读取标准输入,将读入的值保存在 vector 元素中。再将vector传递给另一个函数,打印读入的值。记得在恰当的时刻delete vector。
#include <iostream>
#include <vector>using std::vector;vector<int>* alloc_vector()
{return new vector<int>();
}void assign_vector(vector<int>* p)
{int i;while (std::cin >> i){p->push_back(i);}
}void print_vector(vector<int>* p)
{for (auto i : *p){std::cout << i << std::endl;}
}int main()
{auto p = alloc_vector();assign_vector(p);print_vector(p);delete p;return 0;
}
练习12.7
重做上一题,这次使用 shared_ptr 而不是内置指针。
#include <iostream>
#include <vector>
#include <memory>using std::vector;std::shared_ptr<vector<int>> alloc_vector()
{return std::make_shared<vector<int>>();
}void assign_vector(std::shared_ptr<vector<int>> p)
{int i;while (std::cin >> i){p->push_back(i);}
}void print_vector(std::shared_ptr<vector<int>> p)
{for (auto i : *p){std::cout << i << std::endl;}
}int main()
{auto p = alloc_vector();assign_vector(p);print_vector(p);return 0;
}
练习12.8
下面的函数是否有错误?如果有,解释错误原因。
bool b() {int* p = new int;// ...return p;
}
有错误。没有释放指针 p 。
练习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 指向 42,而之前 r 指向的 100 的内存空间并没有被释放,因此会发生内存泄漏。r2 和 q2 都是智能指针,当对象空间不被引用的时候会自动释放。
练习12.10
下面的代码调用了第413页中定义的process 函数,解释此调用是否正确。如果不正确,应如何修改?
shared_ptr<int> p(new int(42));
process(shared_ptr<int>(p));
正确。shared_ptr<int>(p)
会创建一个临时的智能指针,这个智能指针与 p 引用同一个对象,此时引用计数为 2。当表达式结束时,临时的智能指针被销毁,此时引用计数为 1。