为什么我的析构函数显示被释放的指针未分配 C++

Why my destructor shows that pointer being freed was not allocated c++

我想实现2个数组相加,但是当析构到class SList

void operator+(SList list2) {
        int totalLen = this->len + list2.len;
        char** temp = new char* [totalLen];
        for(int i = 0; i < len; i++) {
            temp[i] = this->list[i];
        }
        for(int i = len, j = 0; i < totalLen; i++, j++) {
            temp[i] = list2.get(j);
        }
        delete[] this->list;
        this->list = temp;
        this->len = totalLen;
        cout << len << endl << endl;
    }

这里是return动态数组char的get方法:

char* get(int i) {
        if (i >= len) {
            return "";
        } else {
            return list[i];
        }
    }

这是我的 class SList 私有变量:

private:
    char** list;
    int len;
    char* generateString(){
        char* str;
        int n = rand() % 20 + 1;
        str = new char[n + 1];
        for(int i = 0; i < n; i++) {
            str[i] = 'a' + rand()%26;
        }
        str[n] = '[=12=]';
        return str;
    };
~SList() {
        delete[] list;
    }

它总是在析构函数上显示 malloc 错误。

malloc: *** error for object 0x105007410: pointer being freed was not allocated
malloc: *** set a breakpoint in malloc_error_break to debug

请帮忙!我仔细检查了我在动态分配数组上的删除方法,但它总是显示这个错误。

我已经尝试检查其他函数的其他删除,但是 none 其中出现了相同的 malloc 错误。我试图评论析构函数方法,一切正常。但我真的需要在这里有析构函数方法。我希望对 c++ 有更多专业知识的人可以帮助我修复这个 malloc 错误,并解释我哪里出错了。

不管实现的其他细节是什么,当您使用称为“ragged array”的数据结构时,析构函数是不正确的,即 list 是指向数组的指针指针。 delete[] 会释放指针数组,但不会释放其元素指向的 char 数组。你必须这样做:

~SList() {
    if(!list) return;   // if we cannot guarantee that list isn't 
                        // nullptr we have to check it, 
                        // or result of list[i] would be undefined. 
    for(int i = 0; i < len; i++) 
        delete[] list[i];
    delete[] list;
}

并且您必须确保这些指针中的任何一个都由 new 表达式初始化或等于 nullptr.. 它不会自行发生。您必须确保在施工和所有操作期间。你没有表现出来。在那里寻找错误。

方法 get() 是一个等待发生的灾难并且是 ill-formed,即它不遵循 C++ 规则。字符串文字 "" returns const char*,总是相同的,并且语句 return ""; 是不正确的——尽管一些编译器只对此发出警告。它不能被 delete.

释放
char* get(int i) {
    if (i >= len) {
        return nullptr;  // "" - is not safe
    } else {
        return list[i];
    }
}

删除一个 nullptr 是安全的 no-op。删除 new 未 return 编辑的内容是一场灾难。

加法运算符按值取 list2,这意味着必须执行正确的复制操作。你也没有给他们看。默认实现只会复制一个指针,而本地副本的销毁会释放原来通过上面的 ~SList() 使用的内存。运算符必须 return 结果对象,不应修改 this 指向的对象。您实施了 operator+=。按照你的方式,它会像

 a+b;  // a now contains result of concatenation.

使用起来很奇怪。正确的运算符是

SList operator+(SList& list2);

一般来说,处理某些资源所有权的对象,在我们的例子中是动态内存,必须实现特定的一组特殊成员函数:

 ~SList();
 SList(const SList& other);
 SList(SList&& other); // move copy, source is a temporal.
 SList& operator=(const SList& other);
 SList& operator=(SList&& other); // move assignment

如果做对了,您就可以安全地完成 c = a + b; 作业了。

请注意,如果您通过引用传递参数,则必须考虑到赋值运算符的参数未引用 this 指向的对象,如果引用则相应地采取行动。否则你会破坏它并丢失原始数据。另一方面,由于成本和内存占用量增加,复制参数过多且 user-unfriendly。 n-element 和 m-element 数组的串联预计会有 n+m 个元素的内存占用,而不是 n+2*m.