问题引出?
1、定义如下的类:
class CMessage
{
public:
CMessage(const char *text = "Default Message.")
{
m_pMessage = new char[strlen(text)+1];
strcpy_s(m_pMessage, strlen(text)+1, text);
}
~CMessage()
{
cout<<"Destructor called."<<endl;
delete []m_pMessage;
}
void ShowIt() const
{
cout<<m_pMessage<<endl;
}
private:
char *m_pMessage;
};
2、对该类的使用方式如下:
void DisplayMessage(CMessage localMsg)
{
cout<<"The Messge is :"<<localMsg.ShowIt()<<endl;
return;
}
CMessage aMessage("Jack is wolf.");
DisplayMessage(aMessage);
3、分析:
看起来很简单的代码,但其中存在着致命的错误,问题在于形参,形参是一个CMessage对象,并且函数参数是通过传值方式传递的。调用了该类的默认拷贝构造函数,将发生一系列事件:
- 1)创建aMessage对象,调用类的构造函数,在内存中为传入的参数分配空间。
- 2)调用DisplayMessage函数,因为参数是通过传值方式传递的,所以使用了默认的拷贝构造函数创建了一个实参的副本。现在副本中的指针和原对象的指针指向同一块内存区域。
- 3)DisplayMessage函数结束时,localMsg对象超出作用域,调用CMessage类的析构函数,释放m_pMessage指向的内存,删除这个局部对象。
- 4)从DisplayMessage函数返回时,原来的aMessage对象包含的指针仍然指向刚才已经释放了的区域。如果再次使用aMessage对象时,程序就会出现异常。
4、解决方案:
如果某个类拥有动态定义的成员,又利用按值传递机制给函数传递该类的对象,那么对这个函数的任何调用都将出错。
CMessage::CMessage(const CMessage &other)
{
size_t len = strlen(other.m_pMessage);
m_pMessage = new char[len];
strcpy_s(m_pMessage, len, other.m_pMessage);
}
因此:如果动态的为本地C++类的成员分配空间,必须实现该类的拷贝构造函数。