0

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

Q. 在内存管理方面,会发生什么错误?

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;
}

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

请告诉我。谢谢,

4

4 回答 4

1

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

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

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

好读:
什么是三法则?

此外,String对于一个类来说,这是一个糟糕的名字,特别是因为存在一个std::string.

于 2013-04-23T04:34:31.677 回答
1

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

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

于 2013-04-23T04:38:37.380 回答
0

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

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

于 2013-04-23T06:23:23.177 回答
0

您的代码有 4 个问题。

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