【问题标题】:Double Free or Corrupt Error双重免费或损坏错误
【发布时间】:2015-01-26 12:04:54
【问题描述】:

谁能帮我弄清楚为什么我的代码在使用 gnuWin32 时会出现运行时错误。注释 GaussSeidel 函数时,错误消失。我尝试了在线 GNU GCC v4.8.3 编译器,它似乎在那里工作正常。 ideone.com 上的 C++14 给了我运行时错误双重释放或损坏。我附上了我的代码的一个简单版本,它受到该错误的影响。谢谢。

#include <iostream>
#include <cmath>

void GaussSeidel(double** const aa, double* const bb, double* xvec, const int nn, int mm)
{
    int i = 0, j = 0;
    double *ynew=NULL, *yold=NULL, EE=20.0;
    ynew=new double[nn];
    yold=new double[nn];

    while (mm > 0 && EE>0.00001) {
        EE=0.0;
        for (i = 0; i < nn; i++) {
            yold[i]=ynew[i];
            ynew[i] = bb[i] / aa[i][i];
            for (j = 0; j < nn; j++) {
                if (j == i) continue;
                ynew[i] = ynew[i] - (aa[i][j] * xvec[j]/ aa[i][i]);
                xvec[i] = ynew[i];
            }
            if (std::abs(ynew[i]-yold[i])>EE) EE=std::abs(ynew[i]-yold[i]);
        }
        mm--;
    }
    std::cout << mm << "  " << EE << std::endl;

    for (j = 0; j < nn; j++)
        xvec[i] = ynew[i];

    delete [] ynew;
    delete [] yold;
}

int main (void)
{
    int i, j;
    const int Np=100;
    double **Infl=NULL, *Source=NULL, *FpdPhi0=NULL;

    Source=new double[Np];
    FpdPhi0=new double[Np];
    Infl  = new double *[Np]; for(i = 0; i < Np; i++) Infl[i] = new double[Np];

    for (j=0; j<Np; j++){
        for (i=0; i<Np; i++){
            if (i==j){
                Infl[j][i]=1.0;
            }
            else {
                Infl[j][i]=0.0;
            }
        }
        Source[j]=4.0;
        FpdPhi0[j]=0.1;
    }
    GaussSeidel(Infl, Source, FpdPhi0, Np, 300);

    for(i = 0; i < Np; i++) delete [] Infl[i];
    delete [] Infl;
    delete [] Source;
    delete [] FpdPhi0;

    return 0;
}

【问题讨论】:

  • 使用std::vector,摆脱所有无意义的手动内存管理。
  • 此外,如果在该函数中第二次调用 new[] 引发异常,则您的 GaussSeidel 存在内存泄漏。使用std::vector 可以避免所有这些问题。
  • 限制for循环索引变量的范围是个好主意。
  • 谢谢大家的回复。如果我使用向量类而不是指针,需要多少内存?它必须更正确?我的问题是内存密集型问题,我正在尝试节省内存。
  • @mokk 每个向量的区别是sizeof(std::vector&lt;double&gt;) - sizeof(double*)

标签: c++


【解决方案1】:

函数中的最后一个循环使用i 作为索引,此时它可能等于nn 并且超出范围。您可能打算使用循环变量j

因此,您访问了 xvec 数组范围之外,这是未定义的行为,并且可能会在删除之前损坏其他内部定义的数组之一

【讨论】:

    【解决方案2】:

    我可以确定可能的贡献者。

    ynew 和 yold 都是动态分配的基本类型(双精度)数组。函数中的第一个操作是在循环中分配 yold[i] = ynew[i](其中 i 从零运行到 nn-1)

    问题在于 operator new 默认初始化了数组的元素。基本类型(double、int、指针等)的默认初始化实际上使它们未初始化(除了在一些特殊情况下,例如静态,当它们被零初始化时)。

    由于“x = y”形式的赋值对 y 进行了所谓的右值到左值转换(一种复杂的说法,即“访问 y 的值,以便可以为 x 分配相同的值”)。右值到左值的转换对未初始化的变量有未定义的行为。

    简而言之:在 GaussSeidel() 中动态分配数组后,您需要在访问元素值之前对其进行初始化。

    快速浏览一下,我没有发现任何其他可能涉及未定义行为的明显问题。

    我还建议考虑使用 std::vector,而不是直接使用运算符 new 和 delete。

    【讨论】:

    • 感谢您的回复。会的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-17
    • 1970-01-01
    • 1970-01-01
    • 2017-11-18
    相关资源
    最近更新 更多