当我浏览这篇文章时,我有一个关于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
}发布于 2013-04-25 06:17:17
当你有这个的时候会发生什么呢?
{
MyString s = "Something";
}这将首先构造一个MyString,它可能会动态分配一个char数组来存储字符串数据。然后s变量就会超出作用域,MyString对象就会被销毁。它的析构函数应该通过执行delete[] str来清理任何动态分配的内存。
假设你像这样使用它:
{
MyString s = "Something";
s = some_other_string;
}现在以相同的方式构造MyString对象,为字符串数据分配内存。然后,第二行将调用赋值操作符。如果它如您所描述的那样实现,则现有的已分配char数组将为deleted,并将分配一个包含与some_other_string相同的字符串数据的新数组。当s超出作用域时,这个新分配的数组将被析构函数销毁。
析构函数只是delete[]s,不管成员str指向什么。在赋值运算符被调用之后,它对新分配的数组执行delete[]操作。
发布于 2013-04-25 06:21:47
当您分配字符串数组来保存rhs内容的副本时,您将覆盖值str。如果在覆盖它之前没有删除它的str,那么您将永远无法从堆中删除它曾经指向的内容。它所指向的内存块仍将保留在堆中,并且不能重用。如果你的程序这样做的次数足够多,你就会用完堆中的空间,你的程序就会死掉。这被称为内存泄漏。
发布于 2013-04-25 07:02:21
首先,您不必在赋值操作符中删除。如果覆盖了指向以前动态分配的内存的指针,则只需删除。MyString的一个更好的实现是也跟踪容量,只有在需要更多容量时才重新分配(并删除)。
此外,在您的实现中,您可以在分配之前删除。如果分配失败,这将导致未定义的行为;您必须在删除之前完成所有可能失败的操作。在这种情况下,您不需要对自赋值进行测试;对自赋值进行测试的必要性通常是赋值操作符损坏的信号。
将这两件事放在一起,我们得到如下结果:
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和长度成员。
https://stackoverflow.com/questions/16203103
复制相似问题