C++中默认的复制构造函数的问题和解决办法

C++中默认的复制构造函数的问题和解决办法

现在介绍程序清单 12.3的两个异常之处(假设输出为该程序清单后面列出的)。首先,程序的输出表明,析构函数的调用次数比构造函数的调用次数多2,原因可能是程序确实使用默认的复制构造函数另外创建了两个对象。当 callme20被调用时,复制构造函数被用来初始化 callme20的形参,还被用来将对象 sailor 初始化为对象 sports。默认的复制构造函数不说明其行为,因此它不指出创建过程,也不增加计数器 num strings 的值。但析构函数更新了计数,并且在任何对象过期时都将被调用,而不管对象是如何被创建的。这是一个问题,因为这意味着程序无法准确地记录对象计数。解决办法是提供一个对计数进行更新的显式复制构造函数:

StringBad::StringBad(const String & s)
{
	num_strings++;
	... // important stuff to go here
}

提示:如果类中包含这样的静态数据成员,即其值将在新对象被创建时发生变化,则应该提供一个显
式复制构造函数来处理计数问题。第二个异常之处更微妙,也更危险,其症状之一是字符串内容出现乱码:

headline2: DÃo

原因在于隐式复制构造函数是按值进行复制的。例如,对于程序清单 12.3,隐式复制构造函数的功能相当于:

sailor.str = sport.str;

这里复制的并不是字符串,而是一个指向字符串的指针。参见【0voice C++】也就是说,将sailor 初始化为 sports后,得到的是两个指向同一个字符串的指针。当 operator<<() 函数使用指针来显示字符串时,这并不会出现问题。但当析构函数被调用时,这将引发问题。析构函数 StringBad 释放 str 指针指向的内存,因此释放 sailor 的效果如下:

delete [] sailor.str; // delete the string that ditto.str points to

sailor.str 指针指向“Spinach Leaves Bowl for Dollars”,因为它被赋值为 sports.str,而 sports.str 指向的正是上述字符串。所以 delete语句将释放字符串“Spinach Leaves Bowlfor Dollars”占用的内存。然后,释放 sports的效果如下:

delete [] sports.str; // effect is undefined

sports.str 指向的内存已经被 sailor 的析构函数释放,这将导致不确定的、可能有害的后果。程序清单12.3 中的程序生成受损的字符串,这通常是内存管理不善的表现。
另一个症状是,试图释放内存两次可能导致程序异常终止。不同的系统可能提供不同的消息,甚至不提供任何消息,但程序中的错误是相同的。

解决类设计中这种问题的方法是定义一个显式复制构造函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值