【问题标题】:Memory allocation error in copy construtor (c++)复制构造函数中的内存分配错误(C++)
【发布时间】:2012-07-31 18:05:57
【问题描述】:

我有一个问题。

我已经用 C++ 编写了相当多的代码。我正在使用 MS Visual Studio 2010。

这是一个类matrix,只有几个简单的数值函数。

以下是实现:

//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;
}

问题是我有一些关于记忆的奇怪错误。

首先,当我像这样调用函数inverse 时:

//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;
}

在函数inverse 中返回值时出错。当我进入 destrutor 并释放内存时出现错误。

但这还不是全部。

当我像这样调用函数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;
}

在这种情况下,函数 gauss 中使用的函数 inverse 也会发生错误,但这次是在将函数 gauss_eq 的结果分配给之前定义的矩阵时。

当我遇到这个问题时,我会去复制构造函数(我不知道为什么),我既不能使用 new 运算符也不能使用 malloc 函数分配内存。

当调试要执行的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);
}

并且参数大小等于68。

我不知道哪里出了问题。

问题出在类矩阵中的构造函数或函数中,还是出在我使用的 C 库中的函数中。

我希望有人花时间研究这个问题,尽管要查看的代码很多。

感谢任何提示。

【问题讨论】:

  • 我敢打赌,如果你用std::vector&lt;double&gt; T 代替double * T,你的大部分问题都会消失。
  • 您能否向我们展示您的构造函数和析构函数的实现,以及反函数的实现?您使用的指向 double 的指针是可疑的,但是如果没有看到使用它的代码,就很难判断它是否是问题所在。
  • 对于初学者来说,你的析构函数和赋值运算符都包含错误的delete。如果可以的话,请采纳@BenjaminLindley 的建议。
  • 所有实现都在第一个代码框中。

标签: c++ memory constructor matrix numeric


【解决方案1】:

我没有阅读你所有的代码,但这绝对是错误的:

matrix::~matrix ()
{
    delete this->T;
}

您需要调用delete[] 运算符,而不是普通的deletenew 必须始终与 delete 匹配,new[] 必须始终与 delete[] 匹配。不这样做是未定义的行为,通常会导致某种内存损坏,从而使您的程序崩溃。

同样,operator = 的实现也应该调用 delete[]

也无需为每个成员访问添加前缀this-&gt;(*this).。它不是惯用的 C++,只应在存在局部变量遮蔽成员变量的情况下使用(这本身并不总是好的做法)。

【讨论】:

  • 我认为,当我使用 ie 时。 n 表示this-&gt;n(*this).n
【解决方案2】:

首先,方式,方式代码太多。但是,问题很简单;您在使用new [] 分配的数组上调用delete。任何用new[] 分配的东西都必须用delete[] 释放。你在operator=也有同样的问题。

【讨论】:

  • 原来没有这么简单。
  • @kostek:删除调用仍然是错误的,你调用了未定义的行为。正如我所说,您发布了很多代码。代码越多,就越不可能有人通过它进行调试。不过很高兴你现在解决了。
【解决方案3】:

您需要使用适当的管理类,而不是自己动手。由于您已经进行了自己的 2D 索引,因此 std::vector&lt;double&gt; 将是一件好事。

【讨论】:

  • 我不会用stl容器,自己写点东西。
  • 然后先写你自己的std::vector替换,然后以此为基础你的Matrix类。
【解决方案4】:

你的赋值运算符是错误的,你写的地方

matrix matrix::operator=(const matrix& A)
{
    if (!(*this==A))

你其实是想写

matrix& matrix::operator=(const matrix& A)
{
    if (this != &A)

您应该检查两个对象的地址是否不相等,而不是矩阵本身不相等(并且 operator= 应该返回一个引用)。

但无论如何,这种风格的赋值运算符是不好的。有一种更好的方法来编写赋值运算符,称为复制和交换习语。它不仅更正确,而且更容易编写。示例见这里

http://programmingexamples.net/wiki/CPP/C%2B%2B0x/TheBigFive

【讨论】:

  • 想一想,说你的赋值运算符是错误的,其实是错误的。这是不寻常的,它可以改进,但它不是不正确的。
  • 我不想检查this 是否与A 指向相同的地址,但如果(*this) 等于A
  • 是的,我现在意识到了。这很不寻常,但并没有错。如果您查看我发布的链接,它确实描述了编写赋值运算符的更好方法。
  • 我研究了复制和交换的想法,对我来说它非常好和简单,所以我接受了你的回答,但它根本没有解决我的问题。
  • 很高兴您接受我的回答,但再次将其带走并不太好。哦,好吧,我相信你做出了正确的决定。
【解决方案5】:

好的。我做了一些更改,现在我像这样释放内存:

matrix::~matrix ()
{
    delete [] this->T;
}

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;
}

但它改变了调用inverse 本身以及gauss 的任何内容。

调试时我停在了

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
}

dbgheap.c.

【讨论】:

  • 但是我认为使用delete [] 我可以释放像double T [100] 这样的静态表。我使用的表是动态的,所以应该使用delete 释放它。
猜你喜欢
  • 2023-04-01
  • 1970-01-01
  • 2015-03-12
  • 2016-07-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多