不好驯服的析构函数
本文假定您对C++的面向对象机制有一些了解,并且对指针比较清楚。您可以随便转载,但是必须保证文章的完整性,并且注明出处。
很愿意和您交朋友:xiaobo68688@qq.com。
注:想问我是学C还是C++的朋友就不要发邮件了,谢谢!
首先看一个深拷贝的例子
可能我写的有点乱,成员变量包括一个指针,其实是一个数组,想要深拷贝。
所以我们需要重载拷贝构造函数。
初学C++的时候,直接记住了参数是引用类型,当时对语言没有深入的理解(虽然现在也不深入),也就没有往心里去,这些天模拟STL,遇到了好多关于深拷贝的问题,而且这问题出的很怪异(我会在下午提出),因此想到了拷贝构造函数,所以在这里需要深究一下。
拷贝构造函数的参数是引用类型。
我们可以试想一下不是引用的情况,也就是说,拷贝构造函数是下边这个样子:
参数传递的是一个对象,按值传递,那么这个对象就会被复制到right,复制的时候又会调用拷贝构造函数,那又会复制一个对象到第二次调用的这个拷贝构造函数里边,因此又需要第三次调用拷贝构造函数。。。想一下,是不是无限循环?
简单地说:传值需要调用拷贝构造函数,而不是引用类型的拷贝构造函数又需要调用拷贝构造函数。因此无限循环。
Ok,把引用的这个问题说明白,下边说一下我这几天遇到的这个问题:
请先看一段代码:
可以试着运行一下,在我电脑上边出现了下边这个错误
很恐怖的错误。呵呵,让我们详细分析一下。
第一次a.show()成功,说明对象a建立没有问题;b.show()失败,说明没有复制成功;第二次a.show()失败,说明a被修改了,可以猜想一下,是不是被调用了析构函数?
现在重载 = 的时候是按值传递,那么,我们传进去的是地址p和size。
之后是执行拷贝的函数,这个没啥问题,把right中的相关数据拷贝。
然后就开始执行析构函数了,首先析构的是传进来的参数,也就是right,由于right的p和主函数中a的p相等,因此right的p被delete了也就是a的p被delete了,在这里,我们把主函数中的a不小心析构了一点点(把p给delete了)。因为函数的返回的是值,所以第二步析构的是(*this),这样,就把复制后的p给delete了。到这里,我们悲剧地把内存中所有的p都delete了。
所以,当再次输出a和b的时候,全都是随机值。
细心的朋友可能会发现,当第二次输出a和b的时候仍然是输出了10个,也就是开始的size值。a的size是10不难理解。由于析构函数是在函数返回后调用的,所以返回的b的size是不改变的(返回是在改变以前)。
我们试着改一下:
下边是我在参数上边加了&,这样,当再次输出a的时候没有错误
下边是在参数right和返回值都加了&, 这样就没有错误了 。
正好符合我们的分析。