练习13.9
①析构函数是什么?
②合成析构函数完成什么工作?
③什么时候会生成合成析构函数?
解答:
①析构函数执行与构造函数相反的操作:构造函数初始化对象的非static数据成员,还可能做一些其他工作;析构函数释放对象使用的资源,并销毁对象的非static数据对象。
②其实就和析构函数完成的工作是一样的
③当一个类没有定义自己的析构函数的时候,编译器会为它定义一个合成析构函数。
练习13.10
当一个StrBlob对象销毁时会发生什么?一个StrBlobPtr对象销毁时呢?
解答:
这里可以参考析构函数完成什么工作。
在一个构造函数中,成员的初始化是在函数体执行之前完成的,且按照他们再类中出现的顺序进行初始化。再一个析构函数中,首先执行函数体,然后销毁成员。成员按照初始化顺序的逆序销毁。
练习13.11
在前面练习中的HasPtr类添加一个析构函数。
解答:
#include <iostream>
#include <string>
using namespace std;
class HasPtr{
public:
HasPtr(const string &s = string()):ps(new string(s)), i(0){}
//HasPtr(const HasPtr& ori):ps(new string(*(ori.ps))), i(ori.i){};
HasPtr& operator=(const HasPtr& ori){
ps = new string(*(ori.ps));
i = ori.i;
return *this;
}
~HasPtr(){ // 添加析构函数
delete ps;
}
//private:
string *ps;
int i;
};
int main(){
HasPtr a("test string");
cout << a.ps << endl;
cout << *(a.ps) << endl;
HasPtr b;
b = a;
//HasPtr b(a);
cout << b.ps << endl;
cout << *(b.ps) << endl;
}
练习13.12
在下面的代码片段中会发生几次析构函数调用?
bool fcn(const Sales_data *trans, Sales_data accum){
Sales_data item1(*trans), item2(accum);
return item1.isbn() != item2.isbn();
}
解答:
这里可以用一段代码进行替换,来更好的了解
include <iostream>
using namespace std;
class A{
public:
A():a(10){}
~A(){cout << "~A()" <<endl;}
int a;
};
bool fcn(const A *trans, A accum){
A item1(*trans), item2(accum);
return item1.a != item2.a;
}
int main(){
A ori1;
A ori2;
ori2.a = 9;
cout << "function begin" << endl;
cout << fcn(&ori1, ori2) << endl;
cout << "function end" << endl;
}
在begin和end之中有3次析构函数的调用。
这里分别是,
函数第二个参数复制的对象,函数体中构造的两个对象。
这里要注意,当指向一个对象的引用或指针离开作用域时,析构函数不会执行。
练习13.13
理解拷贝控制成员和构造函数的一个好方法是定义一个简单的类,该类定义这些成员,每个成员都打印出自己的名字:
struct X{
X() {std::cout << "X()" << std::endl;}
X(const X&) {std::cout << "X(const X&)"<<std::endl;}
};
给X添加拷贝复制运算符和析构函数,并编写一个程序以不同方式使用X的对象:将它们作为非引用和引用参数传递;
动态分配它们;将它们存放于容器中;诸如此类。观察程序的输出,直到你确认理解了什么时候会使用拷贝控制成员,以及为什么会使用它们。
当你观察程序输出时,记住编译器可以略过拷贝构造函数的调用。
解答:
这道题的意思很明确,要对编译器的行为进行观察。
struct X{
X() {std::cout << "X()" << std::endl;}
X(const X&) {std::cout << "X(const X&)"<<std::endl;}
X& operator=(const X& ori){
std::cout << "operator=()" << std::endl;
//...
}
~X() {std::cout << "~X()" << std::endl;}
//...
};
大概也就是这样。
可以通过不同的编译器编译写好的代码,来观察编译器的实现。