delete []运算符在非常简单的情况下导致分段错误

时间:2016-08-20 23:59:53

标签: c++ arrays pointers segmentation-fault

当我在分配的动态数组(使用delete[]关键字创建)上调用new时,会出现一个非常奇怪的分段错误。起初它是在我删除全局指针时发生的,但它也发生在以下非常简单的情况下,其中delete[] arr

int main(int argc, char * argv [])
{
     double * arr = new double [5];
     delete[] arr;
}

我收到以下消息:

*** Error in `./energy_out': free(): invalid next size (fast):  0x0000000001741470 ***
Aborted (core dumped)

main函数外,我定义了一些相当标准的函数,以及以下函数(在main函数之前定义)

vector<double> cos_vector()
{
    vector<double> cos_vec_temp = vector<double>(int(2*pi()/trig_incr));
    double curr_val = 0;
    int curr_idx = 0;
    while (curr_val < 2*pi())
    {
        cos_vec_temp[curr_idx] = cos(curr_val);
        curr_idx++;
        curr_val += trig_incr;
    }

    return cos_vec_temp;
}

const vector<double> cos_vec = cos_vector();

请注意,在调用main函数之前,cos_vectorcos_vec_temp的返回值将被赋值给全局变量cos_vec

问题是,我知道导致错误的原因:cos_vec_temp应该是一个更大的元素,因为cos_vec_temp[curr_idx]最终会在向量cos_vec_temp的末尾访问一个元素。当我在创建时使cos_vec_temp个元素变大时,不会发生错误。但我不明白为什么它出现在delete[]的{​​{1}}。当我运行gdb时,在arr函数开始处设置断点后,在创建main之后,在检查变量内容时得到以下输出:

arr

在第一个gdb命令中,我显示了(gdb) p &cos_vec[6283] $11 = (__gnu_cxx::__alloc_traits<std::allocator<double> >::value_type *) 0x610468 (gdb) p arr $12 = (double *) 0x610470 向量末尾的元素的内存位置,即cos_vec。第二个gdb命令显示0x610468指针的内存位置,即arr。由于我将0x610470分配给无效的内存位置double,因此我知道它必须部分写在0x610468开头的位置,但这是在0x610470之前完成的。甚至创建(该函数在arr之前调用)。那为什么这会影响main?我原本以为在创建arr时,它并不“关心”以前对那里的内存位置做了什么,因为它没有被注册为正在使用中。

任何澄清都将不胜感激。

注意:

arr之前已声明为大小为cos_vec_temp的动态双数组(与代码中的大小相同,但使用int(2*pi()/trig_incr)创建)。在这种情况下,我也有如上所述的无效访问,并且当我访问该位置的元素时它也没有给出任何错误。但是当我试图在new全局变量(类型为delete[])上调用cos_vec时,它也会出现分段错误,但它没有给出我得到的消息上面的案例。

注2:

在你投票使用动态数组之前,我很好奇为什么会这样。我通常使用STL容器及其所有便利(我几乎从不使用动态数组)。

2 个答案:

答案 0 :(得分:3)

许多堆分配器将元数据存储在它为内存分配的内存旁边,在内存之前或之后(或两者)。如果你写出一些堆分配内存的边界(并记住std::vector动态分配堆),你可能会覆盖一些元数据,破坏堆。

这些都不是在C ++规范中实际指定的。所有这一切都说超出界限会导致未定义的行为。分配器执行或存储的内容以及可能存储元数据的位置取决于实现。

对于解决方案,大多数人都会告诉您使用push_back而不是直接索引,并且解决问题。不幸的是,这也意味着需要重新分配和复制向量几次。这可以通过reserving预先大约的内存量来解决,然后让额外的杂散元素导致重新分配和复制。

或者当然,可以更好地预测矢量将包含的实际元素数量。

答案 1 :(得分:1)

看起来你正在编写在main之前执行的函数中分配的向量的末尾,稍后会导致未定义的行为。

你应该能够通过在分配向量时向上舍入数字来解决问题(转换为int将数字向下舍入),或者使用push_back而不是索引:

cos_vec_temp.push_back(cos(curr_val));