简体   繁体   English

String(const char*) 构造函数 memory 泄漏字符串 class

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

So I was trying to implement String class and I got an error saying segmentation fault.所以我试图实现 String class 并且我得到一个错误,说分段错误。 I think there is memory leak in my constructor.我认为我的构造函数中有 memory 泄漏。 Can you please tell me what I am doing wrong?你能告诉我我做错了什么吗? Thank you.谢谢你。

here is the constructor code and I am not permitted to use any standard library functionality.这是构造函数代码,我不允许使用任何标准库功能。

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

And also this is my full code:这也是我的完整代码:

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

The problem with your String(const char* chars) constructor is on this statement:您的String(const char* chars)构造函数的问题在于以下语句:

str = new char[len - 1];

You are allocating less memory then you need, so your for loop is going out of bounds of the allocated memory.您分配的 memory 比您需要的少,因此您的for循环超出了分配的 memory 的范围。 You need to allocate at least len number of chars, not len - 1 number of chars:您需要分配至少len个字符,而不是len - 1个字符:

str = new char[len];

If you intend str to be null-terminated, you need to allocate len + 1 number of chars instead, and then insert a null terminator after the loop is finished:如果您打算str以空值终止,则需要分配len + 1个字符,然后在循环完成后插入 null 终止符:

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

You are making a similar mistake in your toChars() method.您在toChars()方法中犯了类似的错误。 You are not null-terminating the output, which is required by the operator<< that you are passing the memory to afterwards:您没有对 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;
}

Note that I removed the noexcept on toChars() .请注意,我删除了toChars()上的noexcept This is because new[] is not noexcept , it can throw a std::bad_alloc exception if it can't allocate memory, which you are not catching.这是因为new[]不是noexcept ,如果它不能分配 memory,它会抛出一个std::bad_alloc异常,而你没有捕捉到。 noexcept means the method doesn't throw any exception at all, but that is not the case here. noexcept表示该方法根本不会throw任何异常,但这里不是这种情况。

There are other problems with your code, too:您的代码也存在其他问题:

  • Your destructor leaks memory if len is 0, ie if your Default constructor is called, or your Converting constructor is called with a null/empty string.如果len为 0,即调用 Default 构造函数,或者使用 null/空字符串调用 Converting 构造函数,则析构函数会泄漏 memory。 If you call new[] , you need to call delete[] , regardless of the len used.如果调用new[] ,则需要调用delete[] ,而不管使用的len

  • Your Copy constructor is not initializing str or len if the String being copied is empty.如果要复制的String为空,则 Copy 构造函数不会初始化strlen

  • In main() , you are not delete[] 'ing the memory that toChars() returns.main()中,您不是delete[] 'ing toChars()返回的 memory 。

  • optional for this particular situation, but in general, you are missing a Copy Assignment operator.对于这种特殊情况是可选的,但一般来说,您缺少一个复制分配运算符。 And, since you are clearly using C++11 or later, you should also add a Move constructor and a Move Assignment operator as well.而且,由于您显然使用的是 C++11 或更高版本,您还应该添加一个移动构造函数和一个移动赋值运算符。 See the Rule of 3/5/0 .请参阅3/5/0 规则

Try this instead (with no additional library functions added, per request):试试这个(没有添加额外的库函数,每个请求):

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

Although, a simpler way to implement toChars() would look like this instead:虽然,实现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;
}

You get crash cause you allocate len - 1 chars new char[len - 1] , but copy len chars for(int j = 0; j < len; j++) and do not copy zero-char in the end.您会崩溃,因为您分配 len - 1 chars new char[len - 1] ,但复制 len chars for(int j = 0; j < len; j++)并且最后不复制零字符。

The first constructor should be第一个构造函数应该是

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

I hope you are able to update the second constructor properly.我希望您能够正确更新第二个构造函数。

The destructor should be析构函数应该是

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

I hope you are able to fix other issues.我希望您能够解决其他问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM