我正在阅读这篇文章Why do we need to delete allocated memory in C++ assignment operator?,我对在赋值运算符中新操作分配的内存有疑问。在我们分配给MyString对象testObject后它将如何被释放?是否会在超出范围时调用testObject的析构函数,或者我必须显式调用delete以释放该内存?
const MyString& operator=(const MyString& rhs)
{
if (this != &rhs) {
delete[] this->str; // Why is this required?
this->str = new char[strlen(rhs.str) + 1]; // allocate new memory
strcpy(this->str, rhs.str); // copy characters
this->length = rhs.length; // copy length
}
return *this; // return self-reference so cascaded assignment works
}
答案 0 :(得分:3)
当你有这个时会发生什么?
{
MyString s = "Something";
}
这将首先构造一个MyString
,它可能会动态分配一个char
数组来存储字符串数据。然后s
变量超出范围,MyString
对象被销毁。它的析构函数应该通过执行delete[] str
来清理任何动态分配的内存。
让我们说你这样使用它:
{
MyString s = "Something";
s = some_other_string;
}
现在MyString
对象以相同的方式构造,为字符串数据分配内存。然后第二行将调用赋值运算符。如果按照您的描述实现,则现有的已分配char
数组将为delete
d,并且将分配包含与some_other_string
相同的字符串数据的新数组。然后这个新分配的数组,当s
超出范围时,它将被析构函数销毁。
析构函数只是delete[]
s成员str
指向的任何内容。调用赋值运算符后,delete[]
新分配的数组。
答案 1 :(得分:0)
当您分配字符串数组以保存str
内容的副本时,您将覆盖值rhs
。如果在覆盖它之前没有删除str
,则永远无法删除它从堆中指向的内容。它以前指向的内存块仍将保留在堆中,并且不可用于重用。如果你的程序执行了这么多次,那么堆中的空间就会用完,你的程序就会死掉。这称为内存泄漏。
答案 2 :(得分:0)
首先,您不一定要在作业中删除
运营商。如果覆盖指针,则只需删除
以前动态分配的内存。一个更好的
MyString
的实施将是跟踪。{1}}
capactity,如果需要,只重新分配(和删除)
更多的能力。
此外,在您的实施中,您在分配之前删除。 如果分配,这将导致未定义的行为 失败;你必须在之前完成所有可能失败的事情 删除。在这种情况下,您不需要自我测试 分配;自我分配测试的必要性是 通常是你的任务操作员被打破的信号。
将这两件事放在一起,我们得到类似的东西:
MyString const&
MyString::operator( MyString const& other )
{
if ( capacity < other.length ) {
char* tmp = new char[ other.length ];
delete str;
str = tmp;
capacity = other.length;
}
memcpy( str, other.str, other.length );
length = other.length;
return *this;
}
删除是有条件的,分配后删除,
而且我们总是使用length
成员
而不是混合strlen
和长度成员。