388
// assignment operator invoked
// object assigned to itself
// all done
// free old string
// get space for new string
C++Primer Plus(第五版)中文版
StringBad headline1 ("Celery Stalks at Midnight") :
StringBad knot:
knot - headlinel:
初始化对象时,并不一定会使用赋值操作符:
StringBad metoo = knot: // use copy constructor, possibly assignment, too
这里,metoo是一个新创建的对象,被初始化为knot的值,因此使用复制构造函数。不过,正如前面
指出的,实现时也可能分两步来处理这条语句:使用复制构造函数创建一个临时对象,然后通过赋值将临
时对象的值复制到新对象中。这就是说,初始化总是会调用复制构造函数,而使用=操作符时也可能调用
赋值操作符。
(2)赋值操作符的功能
与复制构造函数相似,赋值操作符的隐式实现也对成员进行逐个复制。如果成员本身就是类对象,则
程序将使用为这个类定义的赋值操作符来复制该成员,但静态数据成员不受影响。
6. 賦值的问题出在哪里
程序清单12.3将 headline1 赋给 knot:
knot = headlinel:
为knot调用析构函数时,将显示下面的消息:
"Celery Stalks at Midnight" object deleted, 2 left
为Headline1 调用析构函数时,显示如下消息(有些实现方式在此之前就异常终止了):
"-|" object deleted, -2 left
出现的问题与隐式复制构造函数相同:数据受损。这也是成员复制的问题,即导致 headline1.str和
knot.str指向相同的地址。因此,当对knot调用析构函数时,将删除字符串“Celery Stalks at Midnight”;当
对headline1 调用析构函数时,将试图删除前面已经删除的字符串。正如前面指出的,试图删除已经删除的
数据导致的结果是不确定的,因此可能改变内存中的内容,导致程序异常终止。要指出的是,如果操作结
果是不确定的,则执行的操作将随编译器而异,包括显示独立声明(Declaration of Independence)或者释
放隐藏文件占用的硬盘空间。
7. 解决赋值的问题
对于由于默认赋值操作符不合适而导致的问题,解决办法是提供赋值操作符(进行深度复制)定义。
其实现与复制构造函数相似,但也有一些差别。
● 由于目标对象可能引用了以前分配的数据,所以函数应使用delete[]来释放这些数据。
● 函数应当避免将对象赋给自身;否则,给对象重新赋值之前,释放内存操作可能删除对象的内容。
● 函数返回一个指向调用对象的引用。
通过返回一个对象,函数可以像常规赋值操作那样,连续进行赋值,即如果S0、S1和S2都是StringBad
对象,则可以编写这样的代码:
S0 = S1 = S2:
使用函数表示法时,上述代码为:
so.operator= (S1.operator= (S2) ) :
因此,Sl.operator=(S2)的返回值是函数SO.operator=()的参数。
因为返回值是一个指向StringBad对象的引用,因此参数类型是正确的。
下面的代码说明了如何为StringBad类编写赋值操作符:
StringBad & StringBad :: operator= (const StringBad & st)
if (this == &st)
return *this:
delete [] str:
len = st.len:
str = new char [len + 1]: