I've got a problem.
我有一个问题。
I've already wrote quite a piece of code in C++. I'm using MS Visual Studio 2010.
我已经在c++中编写了相当多的代码。我使用的是Visual Studio 2010。
It's a class matrix
with few simple numerical functions.
它是一个具有几个简单的数值函数的类矩阵。
Below are implementations:
下面是实现:
//matrix.h
#pragma once
#define EPS pow(10., -12.)
#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;
class matrix
{
private:
unsigned int n; //number of columns
unsigned int m; //number of rows
double* T;
public:
matrix ();
matrix (unsigned int _n);
matrix (unsigned int _n, unsigned int _m);
~matrix ();
matrix (const matrix& A);
matrix operator = (const matrix& A);
unsigned int size_n () const;
unsigned int size_m () const;
void ones ();
void zeros ();
void identity ();
void push (unsigned int i, unsigned int j, double v);
void lu ();
void gauss ();
double det ();
void transposition ();
void inverse ();
bool symmetric ();
bool diag_strong_domination ();
void swap_rows (unsigned int i, unsigned int j);
matrix gauss_eq (matrix b);
friend bool operator == (const matrix A, const matrix B);
friend matrix operator + (const matrix A, const matrix B);
friend matrix operator * (const matrix A, const matrix B);
double operator () (unsigned int i, unsigned int j) const;
friend ostream& operator << (ostream& out, const matrix& A);
};
matrix::matrix () : n(0), m(0)
{
this->T = NULL;
}
matrix::matrix (unsigned int _n) : n(_n), m(_n)
{
if (0==_n)
{
this->T = NULL;
return;
}
this->T = new double [(this->n)*(this->m)];
for (unsigned int i=0; i<this->n*this->m; i++)
this->T[i] = (double)0;
}
matrix::matrix (unsigned int _n, unsigned int _m) : n(_n), m(_m)
{
if (0==_m || 0==_n)
throw "Error: Wrong matrix dimensios";
this->T = new double [n*m];
for (unsigned int i=0; i<n*m; i++)
this->T[i] = (double)0;
}
matrix::~matrix ()
{
delete this->T;
}
matrix::matrix (const matrix& A) : n(A.n), m(A.m)
{
this->T = new double [n*m]; //(double*)malloc(A.m*A.n*sizeof(double));
for (unsigned int i=0; i<n*m; i++)
this->T[i] = A.T[i];
}
matrix matrix::operator= (const matrix& A)
{
if (!(*this==A))
{
this->m = A.m;
this->n = A.n;
delete this->T;
this->T = new double [A.n*A.m];
for (unsigned int i=0; i<A.n*A.m; i++)
this->T[i] = A.T[i];
}
return *this;
}
unsigned int matrix::size_n () const
{
return this->n;
}
unsigned int matrix::size_m () const
{
return this->m;
}
void matrix::ones ()
{
for (unsigned int i=0; i<(this->m)*(this->m); i++)
(*this).T[i] = double(1);
return;
}
void matrix::zeros ()
{
for (unsigned int i=0; i<(this->m)*(this->m); i++)
(*this).T[i] = double(0);
return;
}
void matrix::identity ()
{
if (this->m!=this->n)
throw "Error: Matrix have to be square (identity)";
for (unsigned int i=0; i<(this->m)*(this->m); i++)
(*this).T[i] = double(0);
for (unsigned int k=1; k<=this->m; k++)
(*this).push(k, k, (double)1);
return;
}
void matrix::push (unsigned int i, unsigned int j, double v)
{
if (i<=0 || i>this->m || j<=0 || j>this->n)
throw "Error: Indeks out of range (push)";
this->T[(i-1)*this->n + (j-1)] = v;
}
void matrix::lu ()
{
if (this->m!=this->n)
throw "Error: Matrix have to be square (lu)";
if ((*this).diag_strong_domination())
{
//Doolittle decomposition
matrix L(this->m);
matrix U(this->m);
for (unsigned int b=1; b<=this->m; b++)
L.push(b, b, (double)1);
for (unsigned int b=1; b<=this->m; b++)
U.push(1, b, (*this)(1,b));
for (unsigned int b=2; b<=this->m; b++)
{
for (unsigned int c=1; c<=this->m; c++)
{
for (unsigned int k=1; k<=b-1; k++)
{
double s1 = 0;
if (1==k)
s1 = (double)0;
else
for (unsigned int p=1; p<=k-1; p++)
s1 += L(b,p) * U(p,k);
double v = ((*this)(b,k) - s1)/U(k,k);
L.push(b, k, v);
}
for (unsigned int k=b; k<=this->m; k++)
{
double s2 = 0;
for (unsigned int p=1; p<=b-1; p++)
s2 += L(b,p) * U(p,k);
double v = (*this)(b,k) - s2;
U.push(b, k, v);
}
}
}
for (unsigned int p=1; p<=this->m; p++)
L.push(p, p, (double)0);
(*this) = L + U;
for (unsigned int x=0; x<(*this).m*(*this).n; x++)
{
if (abs((*this).T[x])<EPS)
(*this).T[x] = (double)0;
}
return;
}
(*this).gauss();
return;
}
void matrix::gauss()
{
//LU decomposition (gauss elimination with partal choice of main element)
unsigned int n = (*this).m;
matrix U(*this);
matrix svr(1,n);
for (unsigned int a=1; a<=n; a++)
svr.push(a, 1, a);
for (unsigned int k = 1; k<=(n-1); k++)
{
//main element choice - column
unsigned int max = k;
for (unsigned int q=k; q<=n; q++)
{
if (abs(U(q,k)) > abs(U(max,k)))
max = q;
}
unsigned int p = max;
svr.push(k, 1, p);
if (abs(U(p,k)) < EPS)
throw "Error: det = 0";
//main element swap
if (p!=k)
U.swap_rows(p, k);
//elimination
for (unsigned int i=(k+1); i<=n; i++)
{
double tmp = U(i,k)/U(k,k);
for (unsigned int j=(k+1); j<=n; j++)
{
double v = U(i,j) - tmp * U(k,j);
U.push(i, j, v);
}
}
}
if (abs(U(n,n)) < EPS)
throw "Error: det = 0";
for (unsigned int s=2; s<=n; s++)
for (unsigned int t=1; t<=(s-1); t++)
U.push(s, t, (double)0);
matrix T = (*this);
matrix Uinv(U);
Uinv.inverse();
matrix L(n);
for (unsigned int i=1; i<=n; i++)
for (unsigned int j=1; j<=n; j++)
for (unsigned int k=1; k<=n; k++)
{
double v = T(i,k) * Uinv(k,j);
L.push(i, j, v);
}
//reversing rows swap
for (unsigned int t=1; t<=n; t++)
{
if (t!=svr(t,1))
L.swap_rows(t, svr(t,1));
}
(*this) = L + U;
for (unsigned int k=1; k<=n; k++)
(*this).push(k, k, (*this)(k,k) - (double)1);
for (unsigned int x=0; x<(*this).m*(*this).n; x++)
{
if (abs((*this).T[x])<EPS)
(*this).T[x] = (double)0;
}
return;
}
double matrix::det ()
{
if (this->m!=this->n)
throw "Error: Matrix have to be square (det)";
double det = 1;
matrix TMP = (*this);
TMP.lu();
for (unsigned int i=1; i<=this->m; i++)
det *= (double)(TMP(i,i));
return det;
}
void matrix::transposition()
{
matrix R(*this);
for (unsigned int i=1; i<=(*this).m; i++)
for (unsigned int j=1; j<=(*this).n; j++)
(*this).push(j, i, R(i,j));
return;
}
void matrix::inverse ()
{
unsigned int n = (*this).m;
matrix A(*this);
matrix X(n);
matrix b(1,n);
for (unsigned int i=1; i<=n; i++)
{
b.zeros();
b.push(i, 1, (double)1);
X = A.gauss_eq(b); //error when using inverse in gauss function, used in lu
for (unsigned int k=1; k<=n; k++)
(*this).push(i, k, X(k,1));
}
for (unsigned int x=0; x<(*this).m*(*this).n; x++)
if (abs((*this).T[x])<EPS)
(*this).T[x] = (double)0;
return; //error when calling inverse
}
bool matrix::diag_strong_domination()
{
for (unsigned int i=1; i<=n; i++)
{
double s = (double)0;
for (unsigned int j=1; j<=n; j++)
{
if (j!=i)
s += abs((*this)(i,j));
}
if (s>=abs((*this)(i,i)))
return false;
}
return true;
}
void matrix::swap_rows (unsigned int i, unsigned int j)
{
if (i<=0 || i>this->m || j<=0 || j>this->n)
throw "Error: Indeks out of range (swap_rows)";
matrix R(*this);
for (unsigned int p=1; p<=this->m; p++)
for (unsigned int q=1; q<=this->n; q++)
{
if (p==i)
(*this).push(p, q, R(j,q));
if (p==j)
(*this).push(p, q, R(i,q));
}
return;
}
matrix matrix::gauss_eq (matrix b)
{
matrix A(*this);
unsigned int n = this->m;
for (unsigned int k=1; k<=n-1; k++)
{
unsigned int max = k;
for (unsigned int q=k; q<=n; q++)
{
if (abs(A(q,k)) > abs(A(max,k)))
max = q;
}
unsigned int p = max;
if (abs(A(p,k)) < EPS)
throw "Error: det = 0 (gauss_eq)";
if (p!=k)
{
A.swap_rows(p,k);
b.swap_rows(p,k);
}
for (unsigned int i=k+1; i<=n; i++)
{
double tmp = A(i,k) / A(k,k);
for (unsigned int j=k+1; j<=n; j++)
A.push(i, j, A(i,j) - tmp*A(k,j));
b.push(i, 1, b(i,1) - tmp*b(k,1));
}
if (abs(A(n,n)) < EPS)
throw "Error: det = 0 (gauss_eq)";
}
matrix X(1,n);
double s = 0;
for (unsigned int i=n; i>=1; i--)
{
for (unsigned int j=i+1; j<=n; j++)
s = s + (A(i,j)*X(j,1));
X.push(i, 1, (b(i,1)-s)/A(i,i));
s = 0;
}
return X;
}
bool operator == (const matrix A, const matrix B)
{
if (A.size_m()!=B.size_m() || A.size_n()!=B.size_n())
return false;
for (unsigned int i=1; i<=A.size_m(); i++)
for (unsigned int j=1; j<=A.size_n(); j++)
if (A(i,j)!=B(i,j))
return false;
return true;
}
matrix operator + (const matrix A, const matrix B)
{
if (A.m!=B.m || A.n!=B.n)
throw "Error: Wrong dimensions";
matrix R(A.n, A.m);
for (unsigned int i=0; i<A.m*A.n; i++)
R.T[i] = A.T[i] + B.T[i];
return R;
}
matrix operator * (const matrix A, const matrix B)
{
if (A.n!=B.m)
throw "Error: Wrong dimensions";
matrix R(A.m,B.n);
for (unsigned int i=1; i<=R.m; i++)
for (unsigned int j=1; j<=R.n; j++)
for (unsigned int k=1; k<=A.n; k++)
{
double v = R(i,j) + A(i,k) * B(k,j);
R.push(i, j, v);
}
return R;
}
double matrix::operator () (unsigned int i, unsigned int j) const
{
if (i<=0 || i>this->m || j<=0 || j>this->n)
throw "Error: Indeks out of range (operator)";
return this->T[(i-1)*this->n + (j-1)];
}
ostream& operator << (ostream& out, const matrix& A)
{
if (0==A.size_m() || 0==A.size_n())
{
out<<endl<<" [ ]"<<endl;
return out;
}
int s = 10;
out<<endl<<" [ ";
for (unsigned int i=1; i<=A.size_m(); i++)
{
for (unsigned int j=1; j<=A.size_n(); j++)
out<<" "<<setw(s)<<left<<A(i,j)<<" ";
if (i!=A.size_m())
out<<endl<<" ";
}
out<<" ] "<<endl;
return out;
}
And the problem is that i have strange errors concerning memory.
问题是关于记忆我有一些奇怪的错误。
Firstly, when I call function inverse
like that:
首先,当我调用函数逆的时候
//MatLab.cpp
#include <iostream>
#include <complex>
#include <typeinfo>
using namespace std;
#include "matrix.h"
int main()
{
try
{
matrix S(4);
for (unsigned int i=1; i<=S.size_m(); i++)
for (unsigned int j=1; j<=S.size_n(); j++)
S.push(i, j, (double)3);
for (unsigned int i=1; i<=S.size_m(); i++)
S.push(i, i, (double)0);
cout<<"S:"<<S<<endl;
S.inverse(); //<--- here is the problem
cout<<endl<<"S^(-1) = "<<S<<endl;
}
catch (char* xcp)
{
cout<<endl<<xcp<<endl<<endl;
}
system("pause");
return 0;
}
I got error when returning value in function inverse
. When I step into I go to destrutor and have an error while I free memory.
在函数逆返回值时出错。当我进入到destrutor并在我空闲内存时出错。
However it's not all.
然而并不是所有的。
Another strange situation occurs when I call function lu
like this:
另一种奇怪的情况发生在我叫函数lu的时候:
//MatLab.cpp
#include <iostream>
#include <complex>
#include <typeinfo>
using namespace std;
#include "matrix.h"
int main()
{
try
{
matrix S(4);
for (unsigned int i=1; i<=S.size_m(); i++)
for (unsigned int j=1; j<=S.size_n(); j++)
S.push(i, j, (double)3);
for (unsigned int i=1; i<=S.size_m(); i++)
S.push(i, i, (double)0);
cout<<"S:"<<S<<endl;
S.lu(); //<--- here is the problem
cout<<endl<<"LU decomposition"<<S<<endl;
}
catch (char* xcp)
{
cout<<endl<<xcp<<endl<<endl;
}
system("pause");
return 0;
}
In this case error occurs also in function inverse
used in function gauss
, but this time when assigning the result of function gauss_eq
to earlier defined matrix.
在这种情况下,在函数高斯函数中也出现了函数逆,但这一次将函数gauss_eq的结果赋给了先前定义的矩阵。
When I step into that problem I go to copy construtor (I don't know why) and I cannot allocate memory neither with new operator nor with malloc
function.
当我进入这个问题的时候,我就会去复制解释程序(我不知道为什么),我不能分配内存,无论是新的运算符还是malloc函数。
When debugging nex statement to be executed is in malloc.c
file in this function:
在调试nex语句时,将在malloc中执行。c文件在此功能:
__forceinline void * __cdecl _heap_alloc (size_t size)
{
if (_crtheap == 0) {
_FF_MSGBANNER(); /* write run-time error banner */
_NMSG_WRITE(_RT_CRT_NOTINIT); /* write message */
__crtExitProcess(255); /* normally _exit(255) */
}
return HeapAlloc(_crtheap, 0, size ? size : 1);
}
And parameter size equals 68.
参数大小等于68。
I have no idea what can be wrong.
我不晓得什么地方不对劲儿。
Whether the problem is in constructors or functions in class matrix or maybe in function from C libraries I use.
无论问题是在构造函数中,还是在类矩阵中的函数中,或者可能在我使用的C库函数中。
I hope someone devote his time to look into this problem despite it's a lot of code to look over.
我希望有人会花时间去研究这个问题,尽管有很多代码需要检查。
Thanks for any tips.
谢谢你的任何建议。
5 个解决方案
#1
2
I haven't read all your code but this is definitely wrong:
我没有读过你所有的代码,但这绝对是错误的:
matrix::~matrix ()
{
delete this->T;
}
You need to be calling the delete[]
operator, not plain delete
. new
must always be matched with delete
, and new[]
must always be matched with delete[]
. Failure to do is is undefined behavior and will usually result in some sort of memory corruption that will crash your program.
您需要调用delete[]操作符,而不是简单的delete。new必须总是与delete匹配,而new[]必须始终与delete匹配[]。失败是未定义的行为,通常会导致某种内存损坏,从而使程序崩溃。
Likewise your implementation of operator =
should also call delete[]
.
同样,您的操作符=也应该调用delete[]。
There's also no need to prefix every member access with this->
or (*this).
. It's not idiomatic C++ and should only be used in cases where there's a local variable shadowing a member variable (which itself isn't always good practice).
也不需要为每个成员访问这个->或(*this)。它不是惯用的c++,应该只在有局部变量的情况下使用成员变量(它本身并不总是良好的实践)。
#2
2
First, way, way too much code. However, the problem is simple; you call delete
on the array that you allocated with new []
. Anything allocated with new[]
must be deallocated with delete[]
. You have the same problem in operator=
.
首先,方法太多了。然而,问题很简单;您可以在分配给新[]的数组中调用delete。分配给新[]的任何东西都必须被删除[]。在运算符=中也有同样的问题。
#3
2
You need to use an appropriate managing class, not doing it yourself. Since you already do your own 2D indexing, a std::vector<double>
would be a fine thing.
您需要使用一个适当的管理类,而不是自己做。既然您已经完成了自己的2D索引,那么std::vector
#4
0
Your assignment operator is wrong, where you wrote
你的作业操作员错了,你在哪里写的。
matrix matrix::operator=(const matrix& A)
{
if (!(*this==A))
you actually meant to write
你本来打算写的。
matrix& matrix::operator=(const matrix& A)
{
if (this != &A)
You should be checking in the addresses of the two objects are not equal, not if the matrices themselves are not equal (and also operator= should return a reference).
您应该检查两个对象的地址不相等,如果矩阵本身不相等(而且运算符=应该返回一个引用)。
But in any case this style of assignment operator is bad. There's a better way of writing assignment operators called the copy and swap idiom. It's not only more correct it's also easier to write. See here for an example
但在任何情况下,这种赋值操作符都是不好的。有一种更好的方式来编写赋值操作符,称为copy和swap习语。它不仅更正确,而且更容易写。请看这里的一个例子。
http://programmingexamples.net/wiki/CPP/C%2B%2B0x/TheBigFive
http://programmingexamples.net/wiki/CPP/C%2B%2B0x/TheBigFive
#5
0
OK. I've made some changes and now I free memory like that:
好的。我做了一些改变,现在我可以*记忆了:
matrix::~matrix ()
{
delete [] this->T;
}
and
和
matrix& matrix::operator= (const matrix& A)
{
if (!(*this==A))
{
this->m = A.m;
this->n = A.n;
delete [] this->T;
this->T = new double [A.n*A.m];
for (unsigned int i=0; i<A.n*A.m; i++)
this->T[i] = A.T[i];
}
return *this;
}
But it changed anything in both calling inverse
itself as well in gauss
.
但在高斯函数中它改变了两个调用逆本身的性质。
While debugging I stopped at
调试时,我停了下来。
extern "C" _CRTIMP int __cdecl _CrtIsValidHeapPointer(
const void * pUserData
)
{
if (!pUserData)
return FALSE;
if (!_CrtIsValidPointer(pHdr(pUserData), sizeof(_CrtMemBlockHeader), FALSE))
return FALSE;
return HeapValidate( _crtheap, 0, pHdr(pUserData) ); /<-- here I stopped
}
in dbgheap.c
.
在dbgheap.c。
#1
2
I haven't read all your code but this is definitely wrong:
我没有读过你所有的代码,但这绝对是错误的:
matrix::~matrix ()
{
delete this->T;
}
You need to be calling the delete[]
operator, not plain delete
. new
must always be matched with delete
, and new[]
must always be matched with delete[]
. Failure to do is is undefined behavior and will usually result in some sort of memory corruption that will crash your program.
您需要调用delete[]操作符,而不是简单的delete。new必须总是与delete匹配,而new[]必须始终与delete匹配[]。失败是未定义的行为,通常会导致某种内存损坏,从而使程序崩溃。
Likewise your implementation of operator =
should also call delete[]
.
同样,您的操作符=也应该调用delete[]。
There's also no need to prefix every member access with this->
or (*this).
. It's not idiomatic C++ and should only be used in cases where there's a local variable shadowing a member variable (which itself isn't always good practice).
也不需要为每个成员访问这个->或(*this)。它不是惯用的c++,应该只在有局部变量的情况下使用成员变量(它本身并不总是良好的实践)。
#2
2
First, way, way too much code. However, the problem is simple; you call delete
on the array that you allocated with new []
. Anything allocated with new[]
must be deallocated with delete[]
. You have the same problem in operator=
.
首先,方法太多了。然而,问题很简单;您可以在分配给新[]的数组中调用delete。分配给新[]的任何东西都必须被删除[]。在运算符=中也有同样的问题。
#3
2
You need to use an appropriate managing class, not doing it yourself. Since you already do your own 2D indexing, a std::vector<double>
would be a fine thing.
您需要使用一个适当的管理类,而不是自己做。既然您已经完成了自己的2D索引,那么std::vector
#4
0
Your assignment operator is wrong, where you wrote
你的作业操作员错了,你在哪里写的。
matrix matrix::operator=(const matrix& A)
{
if (!(*this==A))
you actually meant to write
你本来打算写的。
matrix& matrix::operator=(const matrix& A)
{
if (this != &A)
You should be checking in the addresses of the two objects are not equal, not if the matrices themselves are not equal (and also operator= should return a reference).
您应该检查两个对象的地址不相等,如果矩阵本身不相等(而且运算符=应该返回一个引用)。
But in any case this style of assignment operator is bad. There's a better way of writing assignment operators called the copy and swap idiom. It's not only more correct it's also easier to write. See here for an example
但在任何情况下,这种赋值操作符都是不好的。有一种更好的方式来编写赋值操作符,称为copy和swap习语。它不仅更正确,而且更容易写。请看这里的一个例子。
http://programmingexamples.net/wiki/CPP/C%2B%2B0x/TheBigFive
http://programmingexamples.net/wiki/CPP/C%2B%2B0x/TheBigFive
#5
0
OK. I've made some changes and now I free memory like that:
好的。我做了一些改变,现在我可以*记忆了:
matrix::~matrix ()
{
delete [] this->T;
}
and
和
matrix& matrix::operator= (const matrix& A)
{
if (!(*this==A))
{
this->m = A.m;
this->n = A.n;
delete [] this->T;
this->T = new double [A.n*A.m];
for (unsigned int i=0; i<A.n*A.m; i++)
this->T[i] = A.T[i];
}
return *this;
}
But it changed anything in both calling inverse
itself as well in gauss
.
但在高斯函数中它改变了两个调用逆本身的性质。
While debugging I stopped at
调试时,我停了下来。
extern "C" _CRTIMP int __cdecl _CrtIsValidHeapPointer(
const void * pUserData
)
{
if (!pUserData)
return FALSE;
if (!_CrtIsValidPointer(pHdr(pUserData), sizeof(_CrtMemBlockHeader), FALSE))
return FALSE;
return HeapValidate( _crtheap, 0, pHdr(pUserData) ); /<-- here I stopped
}
in dbgheap.c
.
在dbgheap.c。