Утечка памяти в конструкторе String (const char *) в классе string - PullRequest
0 голосов
/ 06 апреля 2020

Итак, я пытался реализовать класс String, и я получил сообщение об ошибке сегментации. Я думаю, что утечка памяти в моем конструкторе. Подскажите, пожалуйста, что я делаю не так? Спасибо.

вот код конструктора, и мне запрещено использовать какие-либо стандартные функции библиотеки.

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

Ответы [ 2 ]

0 голосов
/ 06 апреля 2020

Вы получаете cra sh, потому что вы выделяете len - 1 символ new char[len - 1], но копируете len char 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;
}

Надеюсь, вы сможете исправить другие проблемы.

0 голосов
/ 06 апреля 2020

Проблема с вашим конструктором String(const char* chars) заключается в следующем утверждении:

str = new char[len - 1];

Вы выделяете меньше памяти, тогда вам нужно, поэтому ваш for l oop выход за пределы выделенной памяти. Вам нужно выделить как минимум len количество символов, а не len - 1 количество символов:

str = new char[len];

Если вы намерены str завершить нулем, вам нужно вместо этого выделите len + 1 количество символов, а затем вставьте нулевой терминатор после завершения l oop:

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

Вы делаете аналогичную ошибку в вашем методе toChars(). Вы не завершаете вывод на нуль, что требуется для operator<<, которому вы передаете память впоследствии:

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

Обратите внимание, что я удалил noexcept на toChars(). Это потому, что new[] не является noexcept, он может выдать исключение std::bad_alloc, если не может выделить память, которую вы не перехватываете. noexcept означает, что метод не throw вообще исключений, но здесь это не так.

Есть и другие проблемы с вашим кодом, также:

  • Ваш деструктор теряет память, если len равен 0, ie, если вызывается ваш конструктор по умолчанию или ваш конструктор Converting вызывается с нулевой / пустой строкой. Если вы звоните new[], вам нужно позвонить delete[], независимо от используемого len.

  • Ваш конструктор Copy не инициализирует str или len, если String копируется пусто.

  • В main() вы не delete[] сохраняете память, которую возвращает toChars().

  • необязательно для данной конкретной ситуации, но в целом вам не хватает оператора копирования. И, поскольку вы явно используете C ++ 11 или более позднюю версию, вы также должны добавить конструктор Move и оператор Move Assignment. См. Правило 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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...