在函数中使用delete []:为RtlValidateHeap指定的地址无效

Che*_*rus 3 c++ physics heap-memory delete-operator heap-corruption

我正在编写一个程序来解决随时间变化的磁场的Bloch方程.我的磁场值在很大的范围内变化,使用简单的Runge Kutta方法,但我有一个标准的4阶,其恒定的步长设置为与恒定的均匀磁场一起工作.现在我正在尝试使用嵌入式4-5顺序方法来使用截断错误并调整我的步长(ala C中的数字配方中的方法(第2版))

因此,我拥有的功能是:

void rungekuttaKC(double a[6], double b[6][6], double c[6], double cs[6], double h, double gammaN, double bx, double by, double bz, double *mu) {
double *mu5 = new double[3];
mu5 = mu;
double *mu4 = new double[4];
mu4 = mu;
double *kx = new double[6];
double *ky = new double[6];
double *kz = new double[6];
double add[3] = { 0.0, 0.0, 0.0 };
double addmu[3] = { 0.0, 0.0, 0.0 };
double addmus[3] = { 0.0, 0.0, 0.0 };
for (int i = 0; i < 6; i++) {
    for (int j = 0; j < i; j++) {
        add[0] = add[0] + kx[j] * b[i][j];
        add[1] = add[1] + ky[j] * b[i][j];
        add[2] = add[2] + kz[j] * b[i][j];
    }

    kx[i] = h*gammaN*((mu[1] + h*add[1]) * bz - (mu[2] + h*add[2]) * by);
    ky[i] = h*gammaN*((mu[2] + h*add[2]) * bx - (mu[0] + h*add[0]) * bz);
    kz[i] = h*gammaN*((mu[0] + h*add[0]) * by - (mu[1] + h*add[1]) * bx);

}
for (int l = 0;l < 6;l++){
    addmu[0] = addmu[0] + kx[l] * c[l];
    addmu[1] = addmu[1] + ky[l] * c[l];
    addmu[2] = addmu[2] + kz[l] * c[l];

    addmus[0] = addmu[0] + kx[l] * cs[l];
    addmus[1] = addmu[1] + ky[l] * cs[l];
    addmus[2] = addmu[2] + kz[l] * cs[l];
}
for (int m = 0;m <=2; m++) {
    mu4[m] = mu4[m] + addmus[m];
    mu5[m] = mu5[m] + addmu[m];
    mu[m] = mu4[m];
}

//delete[] mu5;
//delete[] mu4;
//delete[] kx;
//delete[] ky;
//delete[] kz;
//delete[] add;
//delete[] addmu;
//delete[] addmus;

}
Run Code Online (Sandbox Code Playgroud)

a,b,c和cs是Cash-Karp方法的Bucher表格中的值,h是步长,1.0e-8.

static double a[6] = { 1.0 / 5.0, 3.0 / 10.0, 3.0 / 5.0, 1.0, 7.0 / 8.0 };
static double bij[6][6] = { {0.0,0.0,0.0,0.0,0.0,0.0},
    {1.0 / 5.0, 0.0, 0.0, 0.0, 0.0, 0.0},
    {3.0 / 40.0, 9.0/40.0, 0.0, 0.0, 0.0, 0.0},
    {3.0/10.0, -9.0/10.0, 6.0/5.0, 0.0, 0.0, 0.0},
    {-11.0/54.0, 5.0/2.0, -70.0/27.0, 35.0/27.0, 0.0},
    {1631.0/55296.0, 175.0/512.0, 575.0/13824.0, 44275.0/110592.0, 253.0/4096.0} };
static double c[6] = { 37.0 / 378.0, 0.0, 250.0/621.0, 125.0/594.0, 0.0, 512.0/1771.0 };
static double cs[6] = {2825.0/27648.0, 0.0, 18575.0/48384.0, 13525.0/55296.0, 277.0/14336.0, 1.0/4.0 };
Run Code Online (Sandbox Code Playgroud)

磁场值由内插器设置在函数外部,并传入,但只是为了确保它产生振荡,我用恒定场测试它,其中bx和by为0,bz为5.传入的内容以{1,0,0}开头

现在,当我不在函数末尾使用任何删除命令时,整个程序在调试器中运行,但是有一个非常明显的内存泄漏.

当我使用只使用new初始化的数组进行删除时,弹出一个窗口,显示错误"Main.exe已触发断点".而没有其他信息.在输出窗口中,我得到"HEAP [Main.exe]:为RtlValidateHeap指定的无效地址(00470000,0016F514)Main.exe已触发断点."

当我在函数末尾删除所有这些时,我得到了相同的错误,但RtlValidateHeap中有一个不同的地址.

我尝试在发布模式下运行,并切换我的运行时库,我得到"检测到严重错误c0000374 Main.exe已触发断点."

我是否误用了删除[]或者还有别的我做错了吗?这个错误是什么意思?

jca*_*cai 6

要删除add,addmuaddmus.这些是在堆栈上分配的(不在堆上new).因此,他们不可能delete[].

由于您在编译时知道数组的所有大小并且它们很小,因此您应该将它们全部分配到堆栈中.对于动态数组,在C++中,最佳实践是使用类似的容器vector,这使您免于delete手动使用的责任.

另外,正如Borgleader所说的那样

double *mu5 = new double[3];
mu5 = mu;
double *mu4 = new double[4];
mu4 = mu;
Run Code Online (Sandbox Code Playgroud)

没有做你期望的事.首先,double[3]在堆上分配a ,并将其地址赋予mu5.然后,删除该地址并用其覆盖mu.当你delete[] mu5,你正在释放所指向的记忆mu(这可能不是意图),并且new double[3]仍然存在.要使用最少的更改来更正它,您可以用该替换该代码段

double *mu5 = new double[3];
std::copy(mu, mu + 3, mu5);
double *mu4 = new double[4];
std::copy(mu, mu + 4, mu4);
Run Code Online (Sandbox Code Playgroud)

但是,写这个是C风格,而不是C++风格(虽然它使用C++语法).