【问题标题】:Memory Management : arrays and dynamic allocation with new operator内存管理:数组和使用 new 运算符的动态分配
【发布时间】:2013-04-23 04:30:52
【问题描述】:

内存管理:使用 new 运算符的数组和动态分配

问。在内存管理方面,会出现什么错误?

class String
{
public:
 String(const char right[]);
 String& operator= (const String& right);
 int length() const;
private:
 char* buffer;
 int len;
}

int String::length() const {return len;}

String::String(const char right[])
{
 len = 0;
 while (right[len] != '\0')
   len++;
 buffer = new char[len+1];
 for (int i = 0; i < len; i++)
   buffer[i] = right[i];
 buffer[len] = '\0';
}

String& String::operator= (const String& right)
{
 if (this != &right)
  { 
    delete[] buffer;
    len = right.length();
    char* buffer = new char[len + 1];
    for (int i = 0; i < len; i++)
      buffer[i] = right[i];
    buffer[len] = '\0';
  }
  return *this;
}

回答。 我不知道...你能帮帮我吗? 这个好像也还行。 新的,它也被删除了。 内存泄漏在哪里?

请告诉我。 谢谢,

【问题讨论】:

  • 你有什么问题?你遇到了什么错误?
  • 除了所有的答案,你应该永远记住一件事:如果你使用运算符new,你应该在某个地方使用运算符delete

标签: c++ memory-management memory-leaks assignment-operator


【解决方案1】:

你需要提供一个构造函数来分配指针成员(事实上你的类的所有构造函数都应该这样做)和解分配它的析构函数。

另外,您需要提供一个复制构造函数来执行指针成员的深层复制。

String::String(const String& obj)
{
   ....
}

好读:
What is The Rule of Three?

另外,String 是一个糟糕的类名称,尤其是因为存在 std::string

【讨论】:

    【解决方案2】:

    Rule of three: 如果一个类定义了析构函数或复制构造函数或复制赋值运算符,它可能必须定义所有这三个。

    您的代码违反了此规则,因为在提供复制赋值运算符时未提供析构函数和复制构造函数。

    【讨论】:

      【解决方案3】:

      您的代码有 4 个问题。

      1. 您的赋值运算符有以下行:char* buffer = new char[len + 1]; 这是声明一个新的指针变量,而不是使用类成员。这会将内存分配给一个指针,然后超出范围并且永远无法删除,这将是内存泄漏并使您的类无法运行。
      2. 缺少析构函数意味着您的类会泄漏内存。您的析构函数负责释放您使用 new[] 分配的内存。
      3. 缺少复制构造函数意味着您的 String 类不能在许多情况下使用,包括在 STL 容器中。 STL 容器要求类型具有公共复制构造函数、赋值运算符和析构函数。
      4. 面对异常,您没有强制执行类不变量。目标是让你的班级exception safe。在我所做的更改中,我试图实现强大的异常保证并在面对异常时保留类状态。考虑异常安全是创建自己的类的一个重要方面——尤其是 String 等库类。

      这是尝试修复所有这些问题的代码。为了保持代码简短,我将实现放入类而不是分离它。当然,在实际代码中你应该使用 std::string。

      class String
      {
      public:
          String() : len(0), buffer(nullptr)
          {}
      
          String(const char right[]) : len(0), buffer(nullptr)
          {
              if(!right)
                  return;
      
              int temp_len = strlen(right);
              buffer = new char[temp_len+1];
              len = temp_len; // only set the length after the allocation succeeds
              strcpy(buffer, right);
          }
      
          // a copy constructor is essential for this class
          String(const String& right) : len(0), buffer(nullptr)
          {
              String temp(right.buffer);
              swap(temp);
          }
      
          // must have a destructor to avoid leaks
          ~String()
          {
              if(buffer) // only delete if it has been allocated
                  delete[] buffer;
          }
      
          String& operator= (const String& right)
          {
              String temp(right.buffer);
              swap(temp);
              return *this;
          }
      
          int length() const
          {
              return len;
          }
      private:
          void swap(String& rhs)
          {
              std::swap(buffer, rhs.buffer);
              std::swap(len, rhs.len);
          }
          char* buffer;
          int len;
      };
      

      【讨论】:

        【解决方案4】:

        当您的 String 对象被销毁时,将调用默认构造函数,因为您没有定义一个。默认析构函数不会为您删除 [] char 数组,您必须声明并定义析构函数才能执行此操作。

        此外,您会发现使用 strcpy()/strncpy() 比复制每个字符的简单循环要快得多。 (至少在使用 GCC 编译时)。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-11-29
          • 2015-04-11
          • 1970-01-01
          • 2013-04-16
          • 1970-01-01
          • 2018-08-29
          • 2013-03-02
          • 1970-01-01
          相关资源
          最近更新 更多