为什么我们需要在C ++赋值运算符中删除已分配的内存?

时间:2011-07-17 08:11:59

标签: c++

为什么我们需要删除声明?

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
}

5 个答案:

答案 0 :(得分:10)

这不是复制构造函数,它是赋值运算符。您需要删除,因为正在分配的对象已经保留了以前的值。

此代码也不是很好,因为首先删除旧值然后分配新值...但是分配可能会抛出异常,在这种情况下,对象将保留指向解除分配区域的指针。更好的方法是首先分配然后删除旧值(永远不允许异常从析构函数中逃脱... see this link for an explanation),这样分配成功或失败而不会损害任何内容。

常见的习惯用法是实现复制构造函数和交换操作(交换两个实例的内容,保证不会抛出异常)。然后实现assignment operator combining the two ...这需要更少的代码,并且从异常处理的角度来看是健壮的。

答案 1 :(得分:5)

答案是你必须释放内存,因为如果没有,那么它就会丢失,因为你正在重新使用指针进行新的分配。无论如何,如果你正在学习运算符,那么在复制结构和无投掷交换方面写operator=是很常见的:

class MyString {
   char* str;
   int len;
public:
   MyString( const MyString& rhs ) : str( new char[ rhs.len ] ), len( rhs.len ) {
      memcpy( str, rhs.str, len );
   }
   ~MyString() {
      delete str;
   }
   friend void swap( MyString & lhs, MyString & rhs ) throw() {
      using std::swap;
      swap( lhs.str, rhs.str );
      swap( lhs.len, rhs.len );
   }
   MyString& operator=( MyString rhs ) { //note: by value
      swap( *this, rhs );
      return *this;
   }
};

请注意,执行的操作类似。现在差异:

  • 整体代码较少。复制时需要执行的任何操作只能在复制构造函数中实现,赋值运算符借用该代码。

  • 无需检查自我分配,因为在旧内存发布之前执行了复制

  • 此实现是异常安全的:如果在分配内存(或复制构造函数中的任何其他操作)时出现问题,则操作没有副作用

  • 自我分配的性能较差,因为新内存已分配,然后被复制和释放。但是临时(rvalue表达式)的赋值会更快,因为编译器可以忽略副本。只有当测量指向代码中的瓶颈时才应考虑性能。

答案 2 :(得分:3)

那不是复制构造函数。那只是一个复制操作员。所以这个> str将指向先前分配的内存。如果在此之前没有释放该内存 - > str被赋予一个新值,那么它将永远不会被释放,因为它的唯一引用已被覆盖。因此,如果没有delete语句,该方法将泄漏内存。

答案 3 :(得分:0)

如果没有delete[]语句,您将分配内存而不再释放它。如果程序运行的时间足够长,最终会耗尽内存。

new char[]调用分配新内存并生成指向已分配内存的指针。您将此内存存储在this->str中 - 覆盖存储在this->str中的先前指针。

答案 4 :(得分:0)

请参阅Scott Meyers,Effective C ++,2nd Ed。,第11至17项,以全面了解该主题。

还有:stackoverflow