所以我有一个名为MatrixMxN的类,在构造函数中它有参数行、列。我正试图为一个维度为行、列的2D数组分配内存,尽管这样做会遇到问题。。(我覆盖括号运算符为每个条目赋值)
{
MatrixMxN coord(4, 1);
coord(0, 0) = 1.0;
coord(0, 1) = 1.0;
coord(0, 2) = 1.0;
coord(0, 3) = 1.0;
}
我面临的问题似乎是当解构器被调用时,我收到错误:-
Windows在MatrixTest.exe中触发了一个断点。这可能是由于堆损坏,这表明MatrixTest.exe或其加载的任何DLL中存在错误。
我的矩阵类中的片段如下所示;
typedef float* floatPtr;
class MatrixMxN {
private:
float** entry;
int rows;
int cols;
public:
MatrixMxN(int r, int c) {
rows = r;
cols = c;
//Create a matrix
if(rows > 0 && cols > 0) {
//Declare an array of pointers
entry = new floatPtr[rows];
//Declare each array
for(int i=0; i<rows; i++) {
entry[i] = new float[cols];
}
this->empty();
}
}
~MatrixMxN() {
//Free memory
for(int i=0; i<rows; i++) {
delete[] entry[i];
}
//Free pointers array
delete[] entry;
}
void empty() {
for(int i=0; i<rows; i++) {
for(int j=0; j<cols; j++) {
entry[i][j] = 0;
}
}
}
// Assignment operator
void operator=(MatrixMxN& other) {
//Check they are the same size
assert(rows == other.rows && cols == other.cols);
//Copy
for(int i=0; i<rows; i++) {
for(int j=0; j<cols; j++) {
entry[i][j] = other(i, j);
}
}
}
float& operator()(const int irow, const int icol) {
//Check they are not out of bounds
assert ( (irow >= 0 && irow < rows) || (icol >= 0 && icol < cols) );
return entry[irow][icol];
}
...
引起错误的部分在循环内部的解构器中;
//Free memory
for(int i=0; i<rows; i++) {
delete[] entry[i];
}
dbgheap.c文件在第一次尝试删除[]条目[i]时抛出错误,其中i=0。虽然在打印矩阵时,它可以正常工作,但这里似乎有一个错误。希望我在这里提供了足够的信息,谢谢。
第1版:包含赋值运算符重载第2版:包含()过载
答案:问题是我是以转置的方式输入值的,而不是我如何输入的。这里的内存被破坏了,谢谢你的帮助。
您应该在一个步骤中分配内存:分配一个M*N个浮点数组,然后计算每次访问的访问位置。您的解除分配也同样简单:删除[]矩阵;
您的类可能会泄漏内存并具有未定义的行为
你有一个巨大而邪恶的错误:你错过了一个合适的复制构造函数。编译器将为您生成一个执行正确操作的程序:复制指针。但这不是你想要的;相反,复制构造函数应该分配新内存并复制数组的内容。
换句话说:使用当前的实现,您很容易泄漏内存并进行双重删除。
选择:
- 阅读"三条规则"
- 使用标准容器(
std::vector
),这些容器具有定义良好的复制语义,并自己管理内存。当您所拥有的只是标准容器时,您甚至根本不需要析构函数、复制构造函数和复制赋值(如果您不以多态方式删除矩阵类)
此外,还有一条风格建议:不要这样使用empty
。所有标准容器都有一个empty()
方法,它的作用与您的完全不同。
这可能不是原因,但没有为类MatrixMxN
定义复制构造函数或赋值运算符:要么定义它们,要么通过声明它们private
使对象不可复制。
虽然本例中没有问题,但如果是rows > 0
而不是cols <= 0
,则会在析构函数中未初始化的指针上调用delete[]
。在构造函数中,entry
仅在rows > 0 && cols > 0
的情况下初始化。如果rows > 0
而不是cols <= 0
,则析构函数中的以下for
循环仍然调用delete[] entry[i];
:
for(int i=0; i<rows; i++) {
delete[] entry[i]; // entry unitialized
}
然后是:
delete[] entry; // entry unitialized
编辑:
operator()
中的assert
不正确:
assert ( (irow >= 0 && irow < rows) || (icol >= 0 && icol < cols) );
它应该使用&&
:
assert ( (irow >= 0 && irow < rows) && (icol >= 0 && icol < cols) );
您的empty()方法正在遍历行和行,而不是行和列。这会损坏内存,当您删除条目时,内存会被捕获。
当你分配元素时,你也可能会破坏内存,因为在你的例子中,你的索引似乎是转置的:
coord(0, 0) = 1.0;
coord(0, 1) = 1.0;
coord(0, 2) = 1.0;
coord(0, 3) = 1.0;
你的意思不是:
coord(0, 0) = 1.0;
coord(1, 0) = 1.0;
coord(2, 0) = 1.0;
coord(3, 0) = 1.0;