簡體   English   中英

String(const char*) 構造函數 memory 泄漏字符串 class

[英]String(const char*) constructor memory leak in string class

所以我試圖實現 String class 並且我得到一個錯誤,說分段錯誤。 我認為我的構造函數中有 memory 泄漏。 你能告訴我我做錯了什么嗎? 謝謝你。

這是構造函數代碼,我不允許使用任何標准庫功能。

String(const char* chars){
            int i = 0;
            if(chars){
                while(chars[i]){
                    i++;
                }
            }
            len = i;
            str = new char[len - 1];
            for(int j = 0; j < len; j++){
                str[j] = chars[j];
            }
        };

這也是我的完整代碼:

#include <iostream>

using namespace std;

class String{
    public:
        char* str;
        int len;
        String(){
            str = new char[0];
            len = 0;
        };

        String(const char* chars){
            int i = 0;
            if(chars){
                while(chars[i]){
                    i++;
                }
            }
            len = i;
            str = new char[len - 1];
            for(int j = 0; j < len; j++){
                str[j] = chars[j];
            }
        };

        String(const String& s){
            if(s.isEmpty() == false){
                len = s.len;
                str = new char[len];
                for(int i = 0; i < len; i++){
                    str[i] = s.str[i];
                }
            }
        };
        ~String() noexcept{
            if(len > 0)
            delete[] str;
        };

        bool isEmpty() const noexcept{
            if(len == 0){
                return true;
            }
            else{
                return false;
            }
        }

        unsigned int length() const noexcept{
            return len;
        }

        const char* toChars() const noexcept{
            char* temp = new char[len];
            int c = 0;
            while(temp[c] != '\0'){
                temp[c] = str[c];
                c++;
            }
            return temp;
        }
};

int main()
{
    const char* chars = "Boo is snoring";
    String s;
    String t{chars};

    cout << "t.len : " << t.length() << endl << "toChar() : " << t.toChars() << endl; 

    return 0;
}

您的String(const char* chars)構造函數的問題在於以下語句:

str = new char[len - 1];

您分配的 memory 比您需要的少,因此您的for循環超出了分配的 memory 的范圍。 您需要分配至少len個字符,而不是len - 1個字符:

str = new char[len];

如果您打算str以空值終止,則需要分配len + 1個字符,然后在循環完成后插入 null 終止符:

str = new char[len + 1];
for(int j = 0; j < len; j++){
    str[j] = chars[j];
}
str[len] = '\0';

您在toChars()方法中犯了類似的錯誤。 您沒有對 output 進行空終止,這是operator<<要求您將 memory 傳遞給之后的:

const char* toChars() const {
    char* temp = new char[len + 1];
    for(int c = 0; c < len; ++c){
        temp[c] = str[c];
    }
    temp[len] = '\0';
    return temp;
}

請注意,我刪除了toChars()上的noexcept 這是因為new[]不是noexcept ,如果它不能分配 memory,它會拋出一個std::bad_alloc異常,而你沒有捕捉到。 noexcept表示該方法根本不會throw任何異常,但這里不是這種情況。

您的代碼也存在其他問題:

  • 如果len為 0,即調用 Default 構造函數,或者使用 null/空字符串調用 Converting 構造函數,則析構函數會泄漏 memory。 如果調用new[] ,則需要調用delete[] ,而不管使用的len

  • 如果要復制的String為空,則 Copy 構造函數不會初始化strlen

  • main()中,您不是delete[] 'ing toChars()返回的 memory 。

  • 對於這種特殊情況是可選的,但一般來說,您缺少一個復制分配運算符。 而且,由於您顯然使用的是 C++11 或更高版本,您還應該添加一個移動構造函數和一個移動賦值運算符。 請參閱3/5/0 規則

試試這個(沒有添加額外的庫函數,每個請求):

#include <iostream>

using namespace std;

class String {
    public:
        char* str = nullptr;
        unsigned int len = 0;

        String() = default;

        String(const char* chars) {
            if (chars) {
                unsigned int i = 0;
                while (chars[i]) {
                    ++i;
                }
                len = i;
                str = new char[len];
                for(int j = 0; j < len; ++j) {
                    str[j] = chars[j];
                }
            }
        }

        String(const String& s) {
            if (!s.isEmpty()) {
                len = s.len;
                str = new char[len];
                for(int i = 0; i < len; ++i){
                    str[i] = s.str[i];
                }
            }
        }

        ~String() noexcept {
            delete[] str;
        }

        String& operator=(const String &s) {
            if (&s != this) {
                String tmp(s);
                char *tmpstr = tmp.str;
                unsigned int tmplen = tmp.len;
                tmp.str = str;
                tmp.len = len;
                str = tmpstr;
                len = tmplen;
            }
            return *this;
        }

        bool isEmpty() const noexcept {
            return (len == 0);
        }

        unsigned int length() const noexcept {
            return len;
        }

        const char* toChars() const {
            char* temp = new char[len + 1];
            for(unsigned int c = 0; c < len; ++c) {
                temp[c] = str[c];
            }
            temp[len] = '\0';
            return temp;
        }
};

int main()
{
    String t{"Boo is snoring"};

    const char *chars = t.toChars();
    cout << "t.len : " << t.length() << endl << "toChar() : " << chars << endl; 
    delete[] chars;

    return 0;
}

雖然,實現toChars()的更簡單方法看起來像這樣:

#include <iostream>

using namespace std;

class String {
    public:
        char* str = nullptr;
        unsigned int len = 0;

        String() = default;

        String(const char* chars) {
            if (chars) {
                unsigned int i = 0;
                while (chars[i]) {
                    ++i;
                }
                len = i;
                str = new char[len + 1];
                for(int j = 0; j < len; ++j) {
                    str[j] = chars[j];
                }
                str[len] = '\0';
            }
        }

        String(const String& s) {
            if (!s.isEmpty()) {
                len = s.len;
                str = new char[len + 1];
                for(int i = 0; i < len; ++i){
                    str[i] = s.str[i];
                }
                str[len] = '\0';
            }
        }

        ~String() noexcept {
            delete[] str;
        }

        String& operator=(const String &s) {
            if (&s != this) {
                String tmp(s);
                char *tmpstr = tmp.str;
                unsigned int tmplen = tmp.len;
                tmp.str = str;
                tmp.len = len;
                str = tmpstr;
                len = tmplen;
            }
            return *this;
        }

        bool isEmpty() const noexcept {
            return (len == 0);
        }

        unsigned int length() const noexcept {
            return len;
        }

        const char* toChars() const noexcept {
            return str ? str : "";
        }
};

int main()
{
    String t{"Boo is snoring"};

    cout << "t.len : " << t.length() << endl << "toChar() : " << t.toChars() << endl; 

    return 0;
}

您會崩潰,因為您分配 len - 1 chars new char[len - 1] ,但復制 len chars for(int j = 0; j < len; j++)並且最后不復制零字符。

第一個構造函數應該是

String(const char* chars) {
  len = 0;
  if (chars) {
    while (chars[len])
      len++;
  }
  str = new char[len + 1];
  for (int j = 0; j < len; j++){
    str[j] = chars[j];
  }
  str[len] = 0;
};

我希望您能夠正確更新第二個構造函數。

析構函數應該是

~String() noexcept{
  delete[] str;
}

我希望您能夠解決其他問題。

暫無
暫無

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

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