以前在学校学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!

|