C++拷贝
第一遍看这部分(P452)确实很难理解,回头对照英文的再看看。
拷贝
HasPtr类
这一小节开篇第一句话就让我头大。“管理类外资源的类必须定义拷贝控制成员”
通过不断翻书追根溯源,我捋了一下如何理解这句话。首先我们来看书中所提供的HasPtr类(我这里省略了std作用域):
class HasPtr{ public: //动态分配一个新的string HasPtr(const string &s = string()): ps(new string(s)), i(0) { } //拷贝对象p到ps指向的地址 HasPtr(const HasPtr& p): ps(new string(*p.ps)), i(*p.i) { } private: string *ps; int i; };
HasPtr(const string &s = string()): ps(), i() { }
构造函数的默认实参s是一个string类型的引用,为空字符串;冒号后面是数据成员ps和i的初值。
HasPtr(const HasPtr& p): ps(new string(*p.ps)), i(*p.i) { }
拷贝构造函数,把p的成员函数ps的地址和i值赋给新的对象
Synthesied copy constructor
如果没有为类定义一个拷贝构造函数,编译器会为我们定义一个synthesied copy constructor。
等价于如下的copy constructor:
class Sales_data{ public: Sales_data(const Sales_data&); private: string bookNo; int units_sold=0; double revenue = 0.0; } Sales_data::Sales_data(const Sales_data &orig): bookNo(orig.bookNo), units_sold(orig.units_sold), revenue(orig.revenue) { }
可以发现synthesied copy constructor把成员数据的默认值赋给对象orig。
Synthesied destructor
当类未定义自己的析构函数时,编译器会为它定义一个合成析构函数(synthesied destructor)
class Saled_data{ public: ~Sales_data() { } ... };
从代码中可以看到,合成析构函数只销毁其成员,而动态分配的指针则需要使用delete来销毁。
因此需要类来定义一个析构函数。
三五法则
需要析构函数的类也需要定义拷贝构造函数和拷贝赋值运算符
class HasPtr{ public: HasPtr(const string &s = string()): ps(), i() { } ~HasPtr() { delete ps; } ... };
假如我们为HasPtr类定义了一个析构函数,但是使用的是合成版本的拷贝构造函数,那么看下面这个函数:
HasPtr f(HasPtr hp){ HasPtr res = hp; return res; }
对象hp接受类HasPtr数据成员的默认值。
将对象hp作为参数传入函数f();将hp的内存地址赋给res;函数声明周期结束时销毁res和hp,这两个对象都会调用HasPtr的析构对象。