【问题标题】:freeing memory allocated by assignment operator C++释放由赋值运算符 C++ 分配的内存
【发布时间】:2013-04-18 15:50:33
【问题描述】:

我正在阅读这篇文章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
}

【问题讨论】:

  • 它应该在析构函数中被释放,如果你已经正确实现它。
  • 不完全是重复的,但是如果你要写一个资源管理类,你需要知道所有关于Rule of Three的知识。
  • 是的,我知道,但是析构函数会释放赋值运算符中分配的内存吗?我认为它只会释放复制构造函数中分配的内存。
  • @vkaul11:析构函数应该包含delete[] str;,它将释放最近分配的数组,无论它是在哪里分配的。这也是为什么您需要删除该运算符中的旧数组,然后在下一行覆盖指向它的指针。
  • 析构函数将释放它被指示释放的任何内存。

标签: c++


【解决方案1】:

当你有这个时会发生什么?

{
  MyString s = "Something";
}

这将首先构造一个MyString,它大概会动态分配一个chars 的数组来存储字符串数据。然后s 变量超出范围,MyString 对象被销毁。它的析构函数应该通过delete[] str 清理所有动态分配的内存。

假设你像这样使用它:

{
  MyString s = "Something";
  s = some_other_string;
}

现在MyString 对象以相同的方式构造,为字符串数据分配内存。然后第二行将调用赋值运算符。如果按照您描述的那样实现,则现有分配的char 数组将是deleted,并且将分配一个包含与some_other_string 相同的字符串数据的新数组。当s 超出范围时,这个新分配的数组将被析构函数销毁。

无论成员str 指向什么,析构函数就是delete[]s。赋值运算符被调用后,就是delete[]新分配的数组。

【讨论】:

  • 感谢您的回答。这很清楚。我在想,好像只为构造函数分配的内存而不是赋值运算符调用析构函数。
  • 虽然解释是好的,但它忽略了指出你必须在释放旧的内存块之前分配新的内存块,或者至少,你必须确保分配新的成员指针不指向已删除的块。
【解决方案2】:

当您分配字符串数组来保存rhs 内容的副本时,您将覆盖值str。如果您在覆盖之前没有删除str,您将永远无法从堆中删除它曾经指向的内容。它曾经指向的那个内存块仍将保留在堆中,并且无法再使用。如果您的程序执行此操作的次数足够多,您将耗尽堆中的空间并且您的程序将死亡。这称为内存泄漏。

【讨论】:

    【解决方案3】:

    首先,您不一定要在作业中删除 操作员。如果你覆盖一个指针,你只需要删除 到以前动态分配的内存。一个更好的 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 和长度成员。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-03-14
      • 2014-10-16
      • 2018-08-29
      • 2013-02-28
      • 1970-01-01
      • 1970-01-01
      • 2014-12-11
      • 1970-01-01
      相关资源
      最近更新 更多