C++Prime 第十三章 前30题

    技术2022-07-11  91

    C++Prime 第十三章 前30题

    练习13.1

    拷贝构造函数:通过拷贝对象的方式创建一个新对象.满足以下条件:本身是构造函数,第一个参数必定是自身类类型的引用,且任何额外参数都有默认值. 使用:"=";函数非引用形参;非引用返回值;用花括号初始化一个数组中的元素或者一个聚合类中的成员;某些类类型会对他们所分配的对象使用拷贝初始化.

    练习13.2

    拷贝构造函数第一个参数必须是对自身类类型的引用,不然会陷入无限的递归调用中. 本题,如定义Sales_data a = b; 则相当于 a.Sales_data(b);将实参b传给了形参rhs. 则相当于 rhs.Sales_data(b); 再次将实参b传给了形参rhs,无限循环.

    练习13.3

    共享指针引用数加一,弱指针的复制不会影响引用计数.

    练习13.4

    除了*heap= local 使用的拷贝赋值运算符外,其余均是使用的拷贝构造函数.

    练习13.5

    HasPtr(const HasPtr & hp) { HasPtr tmp; tmp.ps = new string(hp.ps); tmp.i = hp.i; return tmp; }

    练习13.6

    拷贝赋值运算符:本质是成员函数,是一个重载的赋值运算符,左侧是隐含的this指针,右侧是指向类类型的对象,函数返回左侧参数的引用. 赋值的时候使用. 合成拷贝赋值运算符:对于某些类,禁止该类型对象的赋值,一般情况是:将右侧运算对象的每个非static成员赋值给左侧运算对象的相应成员. 当类未定义自己的拷贝赋值运算符时,会生成合成的拷贝赋值运算符.

    练习13.7

    会赋值,区别是共享指针的赋值会使引用计数++,而弱指针不会增加引用计数.

    练习13.8

    HasPtr& operator=(const HasPtr & hp) { delete ps; ps = new string(hp.ps); i = hp.i; return *this; }

    练习13.9

    析构函数:是类的一个成员函数,其名字由波浪线加类名组成,没有返回值也不接受参数,会释放对象使用的资源,并销毁对象的非static数据成员. 合成析构函数的工作:某些类用来阻止该类型的对象被销毁,如果不是这种情况,函数体就为空. 未定义自己的析构函数时,编译器会合成默认的析构函数.

    练习13.10

    StrBlob:所有成员被销毁,共享指针引用计数–,如果为0,则销毁共享指针所指对象. StrBlobStr:所有成员被销毁.

    练习13.11

    class HasPtr; ~HasPtr() { delete ps; }

    练习13.12

    三次.函数离开作用域时,accum形参被销毁,局部对象item1和item2被销毁.

    练习13.13

    struct X { X() { cout << "X()" << endl; } X(const X&) { cout << "X(const X&)" << endl; } X& operator=(const X&) { cout << "X& operator=(const X&)"; } ~X() { cout << "~X()"; } };

    练习13.14

    全部输出同样的序号.所以这种情况必须使用自定义的赋值构造函数和拷贝构造函数.

    练习13.15

    会.调用了拷贝构造函数.但是要注意,传给f时还要调用拷贝构造,所以最后结果也不是输出a,b,c的序号.

    练习13.16

    会改变.此时传给f的参数是引用,那么就不会调用拷贝构造函数,会直接输出a,b,c的序号.

    练习13.17

    不用编写了,对了.

    练习13.18

    #pragma once #include <iostream> using std::string; class Employee { public: public: Employee() = default; Employee(const std::string& name) :m_name(name) ,m_no(++id){} private: std::string m_name; int m_no = ++id; static int id ; friend std::ostream& operator<<(std::ostream& os, const Employee& e) { os << e.m_name << " " << e.m_no; return os; } };

    练习13.19

    需要删除版的,编译器合成的拷贝控制成员会出错.

    #pragma once #include <iostream> using std::string; class Employee { public: public: Employee() = default; Employee(const std::string& name) :m_name(name) ,m_no(++id){} Employee(const Employee&) = delete; Employee& operator=(const Employee&) = delete; private: std::string m_name; int m_no = ++id; static int id ; friend std::ostream& operator<<(std::ostream& os, const Employee& e) { os << e.m_name << " " << e.m_no; return os; } };

    练习13.20

    对TextQuery: 拷贝:拷贝所有成员,共享指针引用计数加一 赋值:同上 销毁:销毁所有成员,共享指针引用计数减一 对QueryResult: 同上.

    练习13.21

    完全不需要,合成的就足够完成所有工作.

    练习13.22

    HasPtr(const HasPtr & hp) { HasPtr tmp; tmp.ps = new string(hp.ps); tmp.i = hp.i; return tmp; } #pragma once #include <iostream> using std::string; class HasPtr { public: HasPtr(const HasPtr&); HasPtr(const std::string& s = string()) :ps(new string(s)), i(0) {} HasPtr& operator=(const HasPtr&); ~HasPtr() { delete ps; } private: string *ps; int i ; }; #include "HasPtr.h" HasPtr::HasPtr(const HasPtr& hp) { ps = new string(*(hp.ps)); i = hp.i; } HasPtr& HasPtr::operator=(const HasPtr& hp) { auto newp = new string(*hp.ps); delete ps; ps = newp; i = hp.i; return *this; }

    练习13.23

    yes,啊sir

    练习13.24

    未定义析构: 那么每个对象的ps所指向的内存都不会背释放,造成资源泄露. 未定义拷贝控制函数:那么全部是浅复制,造成所有类对象指向同一块内存,一旦某个对象释放掉这块内存,所有对象的ps指针统统变成野指针.

    练习13.25

    练习13.26

    练习13.27

    书上代码比着敲一遍

    练习13.28

    class TreeNode {//有bug,不会整 public: TreeNode(string v = "", int c = 0, TreeNode* l = nullptr, TreeNode* r = nullptr) :value(v), count(c), left(l), right(r) { } TreeNode(const TreeNode& node); TreeNode& operator=(const TreeNode& node); ~TreeNode(); private: std::string value; int count; TreeNode* left; TreeNode* right; }; TreeNode::TreeNode(const TreeNode& node) { value = node.value; count = node.count; left = new TreeNode(*node.left); right = new TreeNode(*node.right); } TreeNode& TreeNode::operator=(const TreeNode& node) { auto leftp = new TreeNode(*node.left); auto rightp = new TreeNode(*node.right); delete left; delete right; left = leftp; right = rightp; count = node.count; value = node.value; return *this; } TreeNode::~TreeNode() { delete left; delete right; }

    练习13.29

    swap(HasPtr&,HasPtr&)中的swap是std::swap,相当于函数内调用了一个其他的函数,自然不会递归调用.

    练习13.30

    inline void swap(HasPtr& h1, HasPtr& h2) { std::cout << "Swap()""被执行了" << std::endl; using std::swap; swap(h1.ps, h2.ps); swap(h1.i, h2.i); }

    测试:

    HasPtr h1, h2; swap(h1, h2);
    Processed: 0.011, SQL: 9