为什么我的C++程序有时会在离开方法时崩溃
Why does my C++ program sometimes crash upon leaving a method
我正在尝试编写一个小库来实现矩阵和对它们的一些基本操作。现在我正在尝试实现 LU 分解。问题是我的程序有时运行没有问题,有时它会提前终止,窗口只是说"测试.exe已经超过工作"。
我正在使用具有以下选项的 g++ 进行编译:
g++ "./Lineair Algebra/Matrix.cpp" "./Lineair Algebra/Determinant.cpp" test.cpp -g -lm -std=c++11 -o test.exe
包含文件行列式.cpp,因为我打算使用分解来计算大小为> 3 的行列式。
调用分解的代码正在测试中.cpp:测试.cpp:
#include "./Lineair Algebra/Matrix.hpp"
#include "./Lineair Algebra/Determinant.hpp"
int main (void)
{
Matrix n (4,4);
Matrix& nRef = n;
n.set(0,0,2);
n.set(0,3,1);
n.set(2,0,-2);
n.set(3,0,4);
n.set(1,1,1);
n.set(2,1,-3);
n.set(3,1,-4);
n.set(1,2,3);
n.set(2,2,-5);
n.set(3,2,4);
n.set(0,3,1);
n.set(1,3,-3);
n.set(2,3,2);
n.set(3,3,6);
Matrix tmp1 (4,4);
Matrix tmp2 (4,4);
Matrix& tmp1Ref = tmp1;
Matrix& tmp2Ref = tmp2;
n.print();
cout << "Decomposing" << endl;
n.LUDecompose(tmp1Ref,tmp2Ref);
cout << "Test.cpp regained control" << endl;
n.print();
tmp1.print();
tmp2.print();
cout << "Done printing, returning 0 from test.cpp" << endl;
return 0;
}
矩阵.hpp:
#ifndef MATRIX_HPP
#define MATRIX_HPP
#include <iostream>
#include <vector>
using namespace std;
typedef vector< vector<double> > Table;
class Matrix
{
private:
Table array;
int rows;
int cols;
public:
Matrix();
Matrix(int r, int c);
Matrix(Table t);
~Matrix(void);
//Matrix (double** dp, size_t r, size_t c);
Matrix operator+ (Matrix m);
Matrix operator+ (double d);
Matrix operator- (Matrix m);
Matrix operator- (double d);
Matrix operator* (Matrix m);
Matrix operator* (double d);
void operator*= (double d);
Matrix operator/ (double d);
void operator/= (double d);
bool operator== (Matrix m);
bool operator!= (Matrix m);
bool isSquare () const;
bool isRow () const;
bool isCol () const;
int getElements () const;
int getRows() const;
int getCols() const;
int getSize () const;
double get(int row, int col) const;
void getSubMatrix (int rowFrom, int colFrom, int rowTo, int colTo, Matrix& dest) const;
void getTable (Table& t) const;
int getRow (int row, Matrix& dest) const;
int getCol (int col, Matrix& dest) const;
void set(int row, int col, double value);
void set (Table& t);
void expand (int r, int c);
int addRows (int row, const Matrix& rrm);
int addCols (int col, const Matrix& rcm);
void gaussEliminate (Matrix& lower, Matrix& upper);
int LUDecompose (Matrix& l, Matrix& u);
int transpose (Matrix& dest);
void print ();
};
#endif
Matrix.cpp 大约有 600 行长,所以我将尝试只发布必要的:
矩阵.cpp:构造函数和析构函数(仅用于调试)
#include <iostream>
#include <vector>
#include "Matrix.hpp"
using namespace std;
typedef vector< vector<double> > Table;
Matrix::Matrix()
{
array = Table (1, vector <double> (1));
array[0][0] = 0;
}
Matrix::Matrix(int r, int c)
{
array = Table (c, vector <double> (r));
for (int i = 0; i < r; i++)
{
for (int j = 0; j < c; j++)
{
this->set(i, j, 0);
}
}
}
Matrix::Matrix(Table t) : array(t) {}
Matrix::~Matrix(void)
{
cout << "Deleting matrix" << endl;
}
矩阵.cpp:LUD组合方法
int Matrix::LUDecompose (Matrix& refLower, Matrix& refUpper)
{
if (!this->isSquare())
{
cout << "Given matrix is not a square matrix" << endl;
return -1;
}
else
{
double c = 0;
Matrix rowMatrix (1,this->getCols());
Matrix& refRowMatrix = rowMatrix;
refUpper = *this;
for (int i = 1; i < this->getRows(); i++)
{
for (int j = 0; j < i; j++)
{
if (i >= j)
{
refUpper.getRow(j,refRowMatrix);
rowMatrix *= refUpper.get(i,j);
rowMatrix /= refUpper.get(j,j);
rowMatrix *= -1.0;
c = refUpper.get(i,j) / refUpper.get(j,j);
refUpper.addRows(i,refRowMatrix);
refLower.set(i, j, c);
cout << "Leaving if statement" << endl;
}
cout << "Leaving inner for loop" << endl;
}
cout << "Leaving outer for loop" << endl;
}
for (int i = 0; i < this->getRows(); i++)
{
refLower.set(i,i,1);
}
cout << "Returning 0 from LUDecompose" << endl;
return 0;
}
}
现在我知道那里有库为我做这件事,但这不是真正的重点,我只是想在这里学习。还要记住,我主要是自学成才的,所以我的代码可能不符合(某些人的)专业标准。
当我在 gdb 之外运行此代码时,这是我得到的输出:
Deleting matrix
Deleting matrix
[2 0 0 1 ]
[0 1 3 -3 ]
[-2 -3 -5 2 ]
[4 -4 4 6 ]
Decomposing
Deleting matrix
Leaving if statement
Leaving inner for loop
Leaving outer for loop
Leaving if statement
Leaving inner for loop
Leaving if statement
Leaving inner for loop
Leaving outer for loop
Leaving if statement
Leaving inner for loop
Leaving if statement
Leaving inner for loop
Leaving if statement
Leaving inner for loop
Leaving outer for loop
Returning 0 from LUDecompose
Deleting matrix
Test.cpp regained control
[2 0 0 1 ]
[0 1 3 -3 ]
[-2 -3 -5 2 ]
[4 -4 4 6 ]
[1 0 0 0 ]
[0 1 0 0 ]
[-1 -3 1 0 ]
[2 -4 4 1 ]
[2 0 0 1 ]
[0 1 3 -3 ]
[0 0 4 -6 ]
[0 0 0 16 ]
Done printing, returning 0 from test.cpp
Deleting matrix
Deleting matrix
Deleting matrix
对于成功运行,或以下操作用于不成功的运行:
Deleting matrix
Deleting matrix
[2 0 0 1 ]
[0 1 3 -3 ]
[-2 -3 -5 2 ]
[4 -4 4 6 ]
Decomposing
Deleting matrix
Leaving if statement
Leaving inner for loop
Leaving outer for loop
Leaving if statement
Leaving inner for loop
Leaving if statement
Leaving inner for loop
Leaving outer for loop
Leaving if statement
Leaving inner for loop
Leaving if statement
Leaving inner for loop
Leaving if statement
Leaving inner for loop
Leaving outer for loop
Returning 0 from LUDecompose
Deleting matrix
从 GDB 运行代码时,它总是崩溃,并且 GDB 产生以下输出:
[New Thread 1584.0x8b8]
[New Thread 1584.0xdb8]
[New Thread 1584.0x13fc]
[New Thread 1584.0x10b8]
Deleting matrix
Deleting matrix
[2 0 0 1 ]
[0 1 3 -3 ]
[-2 -3 -5 2 ]
[4 -4 4 6 ]
Decomposing
Deleting matrix
Leaving if statement
Leaving inner for loop
Leaving outer for loop
Leaving if statement
Leaving inner for loop
Leaving if statement
Leaving inner for loop
Leaving outer for loop
Leaving if statement
Leaving inner for loop
Leaving if statement
Leaving inner for loop
Leaving if statement
Leaving inner for loop
Leaving outer for loop
Returning 0 from LUDecompose
Deleting matrix
warning: HEAP[test.exe]:
warning: Heap block at 00801188 modified at 00801198 past requested size of 8
Program received signal SIGTRAP, Trace/breakpoint trap.
0x76fdee8b in ?? ()
我已经在网上查找了错误,我怀疑这是关于超出范围的事情,但我没有看到为什么。
请温柔一点,这是我第一次提出这样的问题;)
编辑:清理测试.cpp一点,删除了未使用的行列式和矩阵
编辑2:我知道我需要调试这个程序。问题是我不明白为什么它会崩溃。当我在 gdb 中使用 bt 时,它将我指向 de 析构函数和上面的任何帧,这些帧都与向量 (de) 分配器有关。
编辑 3:删除了 =运算符,将构造函数中 [] 的使用更改为 at() 方法。根据要求,这里是设置方法:
void Matrix::set(int row, int col, double value)
{
array[row][col] = value;
}
void Matrix::set (Table& t)
{
if (t.size() > this->getCols())
{
this->expand(0,t.size() - this->getCols());
}
if (t[0].size() > this->getRows())
{
this->expand(t[0].size() - this->getRows(),0);
}
for (int i = 0; i < t[0].size(); i++)
{
for (int j = 0; j < t.size(); j++)
{
this->set(i,j,t[i][j]);
}
}
}
编辑4:更新了构造函数以反映Paul McKenzie的评论
编辑5:很抱歉没有首先发布以下功能,我只是觉得我的帖子已经足够长了......无论如何,你去:
void Matrix::operator*= (double d)
{
for (int i = 0; i < this->getRows(); i++)
{
for (int j = 0; j < this->getCols(); j++)
{
this->set(i, j, this->get(i,j) * d);
}
}
}
void Matrix::operator/= (double d)
{
if (d != 0)
{
for (int i = 0; i < this->getRows(); i++)
{
for (int j = 0; j < this->getCols(); j++)
{
this->set(i, j, this->get(i,j) / d);
}
}
}
else
{
cout << "Can not divide by zero" << endl;
}
}
bool Matrix::isSquare () const
{
if (this->getRows() == this->getCols())
{
return true;
}
else
{
return false;
}
}
int Matrix::getRows() const
{
return this->array.at(0).size();
}
int Matrix::getCols() const
{
return this->array.size();
}
double Matrix::get(int row, int col) const
{
if ((row < this->getRows()) && (col < this->getCols()))
{
return array[row][col];
}
else
{
cout << "Couldn't get (" << row << "," << col <<"), element is out of bounds. dim = " << this->getRows() << " x " << this->getCols() << endl;
return -1;
}
}
int Matrix::getRow (int row, Matrix& dest) const
{
if (!dest.isRow())
{
cout << "Destination matrix is not a row matrix" << endl;
return -1;
}
else
{
for (int i = 0; i < this->getCols(); i++)
{
dest.set(0, i, this->get(row,i));
}
return 0;
}
}
int Matrix::addRows (int row, const Matrix& rrm)
{
if (!rrm.isRow())
{
cout << "Specified matrix is not a row matrix." << endl;
return -1;
}
else if (rrm.getCols() != this->getCols())
{
cout << "Matrix dimensions do not match." << endl;
return -1;
}
else if (row >= this->getRows())
{
cout << "Given row number exceeds amount of rows in matrix." << endl;
return -1;
}
else
{
for (int i = 0; i < rrm.getCols(); i++)
{
this->set(row, i, this->get(row, i) + rrm.get(0,i));
}
return 0;
}
}
编辑6:我通过VS的调试器运行了我的代码,这给了我一个超出范围的异常Matrix::set (int row, int col, double value)
。奇怪的是,我已经更新了进行范围检查的方法。调用堆栈如下所示:
矩阵.cpp::set(整数行,整数列,双精度值) @ 行 415 ( array.at(row).at(col) = value;
)
矩阵.cpp::矩阵(int r, int c) @ line 25 (内部 for 循环的闭合括号)
Matrix.cpp::LUDecompose(Matrix&refLower, Matrix&refUpper) @ line 526 ( Matrix rowMatrix(1, this->getCols());
)
测试.cpp::主@35行(cout << "Test.cpp regained control" << endl;
)
这是该方法当前的样子:
void Matrix::set(int row, int col, double value)
{
if ((row < this->getRows()) && (col < this->getCols()))
{
array.at(row).at(col) = value;
}
else
{
cout << "Trying to assign to (" << row << "," << col << "): Out of bounds, dim = " << this->getRows() << " x " << this->getCols() << endl;
}
}
编辑7:在VS中摆弄了一番后,我能够修复代码。我进行了多次编辑,但我很确定导致上述异常的是 array.at(n)返回第n列(而不是第n行,如我的代码所示)和 array.at(n).at(m)返回位置(m,n)的元素(其中m是第m行,n是第n列)感谢大家对我的帮助,这里有一个固定集方法的副本:
void Matrix::set(int row, int col, double value)
{
if ((row < this->getRows()) && (col < this->getCols()))
{
array.at(col).at(row) = value;
}
else
{
cout << "Trying to assign to (" << row << "," << col << "): Out of bounds, dim = " << this->getRows() << " x " << this->getCols() << endl;
}
}
调试程序的调试版本时,编译器会在代码中插入额外的运行时检查,这对您不可见。这些检查可以检测您是否释放内存两次、使用未初始化的变量、溢出分配的内存块等。这旨在帮助您的程序正在做一些可能未被发现的非法事情。这些检查在发布版本中不存在,因此永远不会显示错误/警告,但您的程序将随机崩溃和/或行为异常。
在这种情况下,您有以下警告:
警告:00801188处的堆块在超过请求大小 8 时修改00801198
运行时检查检测到您在内存位置 00801188 分配了 8 个字节,并且您从此位置开始一直写入超过 8 个字节,一直到 00801198。
这几乎总是指向在循环中使用数组时的问题。下面是一个示例:
假设您分配了 10 个整数的数组:int my[10];
现在,您要将一些值写入每个数组成员:
for ( int i=0; i<=10; i++ ) {
my[i]=some_calculation();
}
这将导致像您这样的确切错误。由于条件是i<=10
(程序员不小心,它应该是i<10
或i<=9
),写入的最后一个成员是my[10]
,第 11 个数组成员,但您只为 10 分配了空间。因此,位于第 10 个成员之后的其他一些内存被覆盖,导致程序中出现不可预测的行为。
最后,检查将值写入数组
成员的所有循环,并确保写入的数组元素数不超过分配的数组元素。
程序崩溃的原因之一是您可能会删除某些内容两次,请检查程序是否在IDE中编译程序
- 为不同配置设置MSVC_RUNTIME_LIBRARY的正确方法是什么
- 通过方法访问结构
- 最小硬币更换问题(自上而下方法)
- C++为构建时间获取QDateTime的可靠方法
- 在C#中处理C++指针而不使用unsafe的最佳方法
- 处理多个异常集合的C++方法
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 有什么方法可以遍历结构吗
- 当类在C++中定义时,有什么方法可以"register"类吗?
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 实现无开销push_back的最佳方法是什么
- 使用std::函数映射对象方法
- 有符号的int和int-有没有一种方法可以在C++中区分它们
- C++从另一个类访问公共静态向量的正确方法是什么
- C++优先级队列,按对象的唯一指针的特定方法升序排列
- 没有为自己的结构调用列表推回方法
- 离开方法时重置变量值
- 为什么我的C++程序有时会在离开方法时崩溃
- 离开时访问违规方法
- 当我离开该方法时,来自静态向量的数据保持不变