双重释放或损坏错误

3

请问有人能帮我解决在使用gnuWin32时代码中运行时出现的错误吗?当注释掉GaussSeidel函数时,该错误消失了。我尝试过在线GNU GCC v4.8.3编译器,它似乎能正常运行。但在ideone.com上使用C++14则出现了double free or corruption的运行时错误。我附上了一个简化版本的代码,其中包含该错误。谢谢。

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

5
使用 std::vector 并消除所有无意义的手动内存管理。 - Chad
2
此外,如果 GaussSeidel 函数中的第二个 new[] 调用抛出异常,则存在内存泄漏问题。通过使用 std::vector 来避免所有这些问题。 - PaulMcKenzie
限制for循环索引变量的范围是一个好主意。 - molbdnilo
谢谢大家的回复。如果我使用向量类而不是指针,需要多少更多的内存?肯定会需要更多吧?我的问题是一个内存密集型的问题,我正在尝试节省内存。 - mokk
@mokk 这个差别是每个向量的 sizeof(std::vector<double>) - sizeof(double*) - molbdnilo
2个回答

4

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

结果是,您访问了xvec数组范围之外的元素,这是未定义的行为,并可能在删除它之前破坏了其他内部定义的数组之一。


0

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

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

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

由于形式为“x=y”的赋值对y执行所谓的rvalue-to-lvalue转换(一种复杂的方式,即“访问y的值,以便可以将相同的值分配给x”)。rvalue-to-lvalue转换在未初始化的变量上具有未定义的行为。

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

快速浏览后,我没有发现其他明显的涉及未定义行为的问题。

与其直接使用new和delete操作符,我建议考虑使用std::vector。


谢谢您的回复。我会去做的。 - mokk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接