C++类中,有时候使用到传值调用(对象实体做参数),遇到这种情况,可要小心了!特别是当你所传值的对象生命周期较长,而非临时对象(生命周期段)的时候。来看看下面的情况:
#include <iostream> using namespace std; class Text { private: char * str;
public :
Text(){str = new char [20];::memset(str,0,20);}
void SetText( char * str)
{
strcpy(this->str,str);
}
char * GetText() const{ return str;}
~Text()
{
cout << "~Text Destruction" << endl;
delete [] str;
cout << "~Text Over" << endl;
}
}; void Print(Text str) { cout << str.GetText() << endl;
} int main()
{ Text t;
t.SetText( "abc" );
Print(t);
return 1;
} |
上面执行的结果程序崩溃了。原因:
Print(Text str)在对str进行复制构造的时候,没有进行深度拷贝;当 Print退出的时候,因为是临时对象(函数初始时构造),对str进行析构,此时还没有任何破绽;但回到main,继而退出main 的时候,又对t进行析构,但此时t内的str中的内容已经被销毁。由于对一内存空间实施了两次销毁,于是出现内存出错。
解决方法:
- 重写浅拷贝。像一下版本,不同的情况要作出适当的调整:
#include <iostream>
using
namespace
std;
class
Text
{
private
:
char
* str;
public
:
Text(){str =
new
char
[20];::
memset
(str,0,20);}
Text(Text &t)
{
str =
new
char
[20];
strcpy
(str,t.GetText());
}
void
SetText(
char
* str)
{
strcpy
(
this
->str,str);
}
char
* GetText()
const
{
return
str;}
~Text()
{
cout <<
"~Text Destruction"
<< endl;
delete
[] str;
cout <<
"~Text Over"
<< endl;
}
};
void
Print(Text str)
{
cout << str.GetText() << endl;
}
int
main()
{
Text t;
t.SetText(
"abc"
);
Print(t);
return
1;
}
- (推荐)不使用传值调用。就像下面书写如下Print版本:
void
Print(Text &str)
{
cout << str.GetText() << endl;
}
- 除非对象内所有的成员读属非指针内存内容,那么谨慎使用文章前面的用法。