我被指出以下文章:
http://www.codeproject.com/Tips/78946/C-Copy-Constructor-in-depth
我们有代码:
class string
{
// constructor
string(char* aStr)
{
str = new char[sizeof(aStr)];
strcpy (str,aStr);
}
// destructor
~string()
{
del str;
}
char *getChars(){ return str; }
char* str;
};
void function (string str)
{
// do something
}
void main ()
{
string str("hello");
function(str);
function(str); // program crashes
}
我不明白为什么在main
中,对function
的第二次调用会出现问题?当str
传递给第一个调用时,这只会是str
的副本,因此str
内function
所做的任何操作都不会影响变量{{} 1}}在str
中声明?
答案 0 :(得分:3)
默认的复制构造函数执行对象的逐位复制。换句话说,指针成员被复制,但不是它指向的对象。如果您使用默认构造函数并且仅执行浅复制,则两个对象中的指针将指向同一对象。
特定于您的问题: 第一次调用 第二次调用 要避免此类问题,您应该定义自己的复制构造函数,该构造函数不仅可以正确复制对象,还可以执行深层复制。 function(str)
一切正常时,当函数结束时,堆栈上的输入参数被销毁(这是str
的副本,但使用默认的复制构造函数指针指向与原始对象相同的位置),将调用其析构函数删除指针指向的对象。 function(str)
时,当函数结束时,析构函数将立即尝试释放str
中指针所指向的地址,然后崩溃。
答案 1 :(得分:2)
问题是str
类中的string
成员是指针。这意味着当创建字符串的副本时,将复制此指针的值,但指针的值只是一个内存位置。因此,当您调用function(str)
时,它正在修改该位置的内存,即使它没有修改指针的值。
答案 2 :(得分:1)
默认情况下,C ++只知道如何使用默认的复制构造函数执行浅层数据复制。所以,是的,对function
的第一次调用确实会产生一个"副本" str
的{{1}},但是这个副本不是副本,因为复制的是字符串类的char*
实例数据。也就是说,C ++只是复制地址,但不够智能,无法为新字符串实际分配空间并复制内容。您必须自己使用自定义复制构造函数。
答案 3 :(得分:0)
str
的构造函数没有为后续调用strcpy
分配足够的字节。之后,所有赌注都已关闭。修复后,编写一个正确的复制构造函数和复制赋值运算符。