我有一个动态重新分配大小的矩阵类。具体来说:动态重新分配行数组。
但在某些情况下,当调用矩阵的析构函数时,会出现内存释放问题:
*** 检测到 glibc *** ./求解器: free(): 无效的下一个大小 (快速): 0x0000000000c112b0 ***
并且该过程正在中止。
矩阵类:
#ifndef __matrix_hpp
#define __matrix_hpp
#include <cstring>
#include <stdexcept>
#include "row.hpp"
using namespace std;
class Matrix {
public:
Matrix();
~Matrix();
size_t size();
void resize(size_t size);
double get(size_t x, size_t y) throw (out_of_range);
void set(size_t x, size_t y, double value) throw (out_of_range);
double getfv(size_t y) throw (out_of_range);
void setfv(size_t y, double value) throw (out_of_range);
void optimize(size_t y) throw (out_of_range);
void _print();
private:
size_t sz;
Row **data;
};
#endif
以及重要功能的主体:
Matrix::~Matrix() {
if (data != NULL) {
for (size_t i = 0; i < sz; ++i)
delete data[i];
delete [] data;
}
}
void Matrix::resize(size_t size) {
if (size == sz)
return;
Row **newData = new Row *[size];
if (data != NULL)
memcpy(newData, data, sz * sizeof(Row*));
if (size > sz) {
for (size_t i = sz; i < size; ++i)
newData[i] = new Row();
}
else {
for (size_t i = size; i < sz; ++i)
delete data[i];
}
delete [] data;
data = newData;
sz = size;
}
所以,这就是代码。当我制作一个矩阵并随后减小它的大小并调用 desctructor 时,问题就来了。例如:
Matrix *matrix = new Matrix();
matrix->resize(10);
matrix->resize(7);
delete matrix;
但是让矩阵变大效果很好:
Matrix *matrix = new Matrix();
matrix->resize(10);
matrix->resize(13);
delete matrix;
最有趣的是,这个例子有效:
Matrix *matrix = new Matrix();
matrix->resize(3);
matrix->resize(2);
delete matrix;
所以我不知道会出什么问题。有什么建议吗?
错误是您在分配的空间之外写入:罪魁祸首是这条线
Row **newData = new Row *[size];
if (data != NULL)
memcpy(newData, data, sz * sizeof(Row*));
如果 sz 大于大小,那么你将写太多,并可能破坏你的堆。将其更改为下面的代码,一切都应该会更好。这样,您将始终复制有效数据,并且不会超过您分配的数据。
Row **newData = new Row *[size];
if (data != NULL)
memcpy(newData, data, (size>sz?sz:size) * sizeof(Row*));
从 3 到 2 的大小调整工作取决于运气(以及堆的工作方式)。
此外,您不会检查新的 Row[] 是否失败,但这会导致 NULL 指针异常。
经过非常粗略的检查,我敢打赌问题是这样的:
if (data != NULL)
memcpy(newData, data, sz * sizeof(Row*));
如果要从 10 缩小到 7,则只需在大小为 7 的缓冲区上复制 10 个指针。
当您分配一些内存并写入超过该内存的末尾时,会发生这种情况,从而覆盖您不拥有的用于管理空闲堆的内存。
查看写入分配内存的每个位置。确保不要写入超过您请求并合法拥有的内存的末尾。