以前在学校学Pascal的时候,产生了一种习惯性的思维:在函数调用时,如果在函数调用前后,不希望参数的值发生改变,那么使用值参;如果希望发生改变,那么使用形参。
在C/C++中,不存在形参,都是值传递的,而引用类似于Pascal中的形参。(我不知道这样说是否恰当)。所以,用C++的时候,我就有这种思维方式:在函数调用时,如果在函数调用前后,不希望参数的值发生改变,那么使用值参;如果希望发生改变,那么使用形参引用。
今天的一个偶然的错误,原来我的想法不对。
问题简化,以下是一个类的定义和实现:
class CA
{
public:
CA(char *a_pcChar = "Test");
virtual ~CA();
private:
char *m_pcChar;
};
CA::CA(char *a_pcChar)
{
if(a_pcChar == NULL)
{
m_pcChar = NULL;
return;
}
m_pcChar = new char[256];
memset(m_pcChar,'\0',sizeof(char) * 256);
strcpy(m_pcChar,a_pcChar);
}
CA::~CA()
{
if(m_pcChar != NULL)
{
delete []m_pcChar;
m_pcChar = NULL;
}
}
然后再定义一个函数:
void test(CA a_clsA)
{
int i = 0;
}
当执行如下代码:
CA clsTmpA("HelloWorld");
test(clsTmpA);
原意是:clsTmpA. m_pcChar 所指的字符串仍然是“HelloWorld”,然而事与愿违的是 clsTmpA. m_pcChar 所值的字符串的值竟然被清掉了。
为什么会这样呢?
思来想去,终于弄明白了。
在执行函数test(clsTmpA)的时候,编译器创建一个clsTmpA的副本,当然,这个副本的m_pcChar所指的地址当然与clsTmpA.m_pcChar的地址相同,此时它们所指向的字符串也是相同的。
但是,当test函数执行完毕退出这个函数时,这个副本也随之消失,因而会执行类CA的修够函数,所以这个副本的m_pcChar指向地址被释放。由于,副本的m_pcChar和clsTmpA.m_pcChar指向的地址相同,在退出函数时,clsTmpA.m_pcChar所指向的字符串被清空也是理所当然的了。
那么,问题怎么解决呢!
把函数 void test(CA a_clsA)改成 void test(CA &a_clsA)就解决了。对于修改后的情况,因为参数就是个函数本身(不是副本),所以在test执行完毕,也不会调用其析构函数。
用VC试试,果真如此,OK!