运行下面的C++代码:
#include<iostream>运行一下,发现输出Hello和乱码,看来第一个Show函数没有问题,第二个Show函数出了问题。原来,在对象作为参数被传递时,参数MyStringCpy复制了对象MyString中的数据成员m_pString,产生了两个CMyString类的对象。由于没有编写拷贝构造函数,这个时候编译器以浅拷贝处理,它们的数据成员m_pString都指向了同一个堆地址,当Show函数调用结束后便会释放对象MyStringCpy,以其首地址作为this指针调用析构函数。在析构函数中,调用delete函数来释放掉对象MyStringCpy的数据成员m_pString所保存的堆空间的首地址。但是对象MyStringCpy是MyString的复制品,真正的MyString还存在,而数据成员m_pString所保存的堆空间的首地址却被释放。
using namespace std;
class CMyString
{
public:
CMyString()
{
m_pString=new char[10];
if(m_pString==NULL)
{
return;
}
strcpy(m_pString,"Hello");
}
~CMyString()
{
if(m_pString!=NULL)
{
delete m_pString;
m_pString=NULL;
}
}
char *GetString()
{
return m_pString;
}
private:
char *m_pString;
};
void Show(CMyString MyStringCpy)
{
printf(MyStringCpy.GetString());
}
int main()
{
CMyString MyString;
Show(MyString);
Show(MyString);
return 0;
}
可以通过深拷贝和设置引用计数来解决这个问题。在引用计数中,每一个对象负责维护对象所有引用的计数值。当一个新的引用指向对象时,引用计数器就递增,当去掉一个引用时,引用计数就递减。当引用计数到零时,该对象就将释放占有的资源。
更好也更简单的办法是在使用类对象作为参数时尽量使用指针或者引用,不但可以避免资源释放的错误隐患,还可以在函数调用过程中避免复制对象的过程,提升程序运行的效率。