size_t length{ strlen(text) + 1 };
m_pMessage = new char[length+1];
strcpy_s(m_pMessage,length,text);
p2.show(); //输出p2的m_PMessage
运行结果:
错误分析:
由于默认复制构造函数的作用是将类对象p1的指针成员储存的地址复制到p2中,因为默认构造函数是值传递,所以这两个对象共享了一个地址的字符串。所以p1中m_PMessage占用的内存被释放后p2的也被释放了,所以p2.show()出来的是一串乱码。而且会听到咚咚咚的 声音,这个窗口要关掉都会卡一下。
如果不显式调用析构函数:
p2.show(); //输出p2的m_PMessage
运行成功,但是会伴随熟悉的咚咚咚的声音,窗口关闭卡顿问题,主要是默认复制构造函数会存在内存的问题。
这就是默认复制构造函数的隐藏风险,这时候就需要自定义复制构造函数了。
在类的public中加入下面的自定义函数:
CMessage(const CMessage& aMess){
size_t len{strlen(aMess.m_pMessage)+1};
m_pMessage = new char[len];
strcpy_s(m_pMessage,len,aMess.m_pMessage);
}
main函数:
int main(void)
{
char * p{"We are the winner"};
CMessage p1{ p };
CMessage p2{p1}; //调用了自定义复制构造函数
p1.~Cmessage(); //显式调用析构函数释放p1占用的内存空间
p2.show();
return 0;
}
运行结果:
分析:
至于为什么会调用了三次析构函数呢,我们这里先不讨论,显示调用析构函数会出现这些问题,如果想具体了解显示调用带来的影响可以去博客查一下。现在我们只看p2中的m_pMessage,看这个运行结果显示这时p2中的m_pMessage没有受到影响,这说明p1和p2没有共享一段内存空间。
如果这时不显示调用析构函数呢
main函数:
int main(void)
{
char * p{"We are the winner"};
CMessage p1{ p };
CMessage p2{p1}; //调用了自定义复制构造函数
p2.show();
return 0;
}
运行结果:
分析:
结果完美,由系统自己去调用析构函数还是更好啊,没有出现内存的一些问题。
当然,结合上面4个实例,这时你会想那如果修改p1中的m_pMessage,会不会带来类似的结果。
这里就需要读者自己去实验咯。
给你布置个小作业就是写个函数如下
void display(CMessage pol)
{
pol.show();
return;
}
你看完这段代码可能会觉得很正常啊,可是我们写这个函数都是习惯了用引用或者指针的方式去传入,这次这个是传值,
空闲储存器中就有了相同的一个副本。给你一个小提示:析构函数的隐式调用是在类对象超出了它的作用域时自动调用的。
欧吼,这是第一次写博客,希望大佬别喷,当然可以提意见,最后希望这些内容对大家学习有帮助。