簡體   English   中英

內存管理:使用新運算符進行數組和動態分配

[英]Memory Management : arrays and dynamic allocation with new operator

內存管理:使用新運算符進行數組和動態分配

問:在內存管理方面,發生了什么錯誤?

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

回答。 我不知道......你能幫幫我嗎? 這個似乎也好。 新的,它也被刪除。 內存泄漏在哪里?

請告訴我。 謝謝,

你需要提供一個構造函數來分配指針成員(實際上你的類的所有構造函數都應該這樣做 )和析構函數來解析它。

此外,您需要提供一個復制構造函數,它執行指針成員的深層復制。

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

好讀:
什么是三法則?

此外, String是一個糟糕的類名,特別是因為存在一個std::string

規則三 :如果類定義析構函數或復制構造函數或復制賦值運算符,則可能必須定義所有三個。

您的代碼在提供復制賦值運算符時不提供析構函數和復制構造函數,從而違反了此規則。

銷毀String對象時,將調用默認構造函數,因為您沒有定義它。 默認的析構函數不會為你刪除[]你的char數組,你必須聲明並定義一個析構函數來執行此操作。

此外,您會發現使用strcpy()/ strncpy()比復制每個char的簡單循環要快得多。 (至少在與GCC編譯時)。

您的代碼有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;
};

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM