C++ 双重释放或损坏(出)

Posted

技术标签:

【中文标题】C++ 双重释放或损坏(出)【英文标题】:C++ double free or corruption(out) 【发布时间】:2020-02-16 13:29:25 【问题描述】:

我在使用带有向量 STL 的迭代器时遇到了这个错误。

代码:-

#include <iostream>
#include <vector>

void print_vec(std::vector<int> vec)

    auto itr = vec.begin();
    while (itr != vec.end())
        std::cout << *itr++ << " ";
    std::cout << std::endl;


int main(int argc, char* argv[])

    std::vector<int> vals =  1, 2, 3, 4, 5, 6 ;
    print_vec(vals);
    auto it = vals.begin();
    vals.insert(it, 100);
    print_vec(vals);
    it += 4;
    std::cout << *it << "\n";
    vals.insert(it, 200);
    print_vec(vals);
    return 0;

输出:-

1 2 3 4 5 6 
100 1 2 3 4 5 6 
5
0 100 1 2 3 4 5 6 
double free or corruption (out)
Aborted (core dumped)

我不明白为什么会这样:修改向量后迭代器有问题吗?我认为我对迭代器的直觉是有缺陷的。

【问题讨论】:

std::vector&lt;int&gt;::iterator itr=vec.begin(); --> auto itr = vector.begin();,拜托。为了可读性。 代码正在与迭代器失效赌博。 【参考方案1】:

当调整std::vector 的大小时,迭代器变得无效,因为它引用了调整大小之前 的向量,这可能包括将向量按顺序移动 到不同的内存位置保持连续性。在这种情况下,it 不会自动更新以引用新位置。

结果在这种情况下(因为它是未定义行为)是值200没有插入向量中,但它被写入了其他一些向量先前占用的堆内存已被释放 - 即您损坏了堆。退出main时vector被销毁,此时系统堆管理失败并报错(事后)。

在插入之后重新分配迭代器可以解决问题:

it = vals.insert(it,100);
...

如您所料,单个项目的输出报告为 5 而不是 4,因为它只是读取尚未重用的旧向量内存并被其他内容覆盖。

您可以通过比较观察错误:

vals.insert(it,100);
std::cout<<std::distance(it,vals.begin())<<'\n' ;

it = vals.insert(it,100);
std::cout<<std::distance(it,vals.begin())<<'\n' ;

您的结果可能会有所不同,但在https://www.onlinegdb.com/,当我执行测试时,第一种情况下迭代器位置和向量开始之间的距离为 16 - 表明迭代器不再引用当前的元素向量状态。在第二种情况下,距离为零 - 迭代器指的是新向量状态的开始。

如果vals 的容量被扩展之前 以迭代器为例:

vals.reserve(10);

然后单个元素的插入不会导致内存移动,并且不会发生失败-尽管不更新迭代器并不是一个好主意-它只是表明发生了什么引擎盖。

【讨论】:

【参考方案2】:

...修改向量后迭代器有问题吗?

是的!

来自cppreference page 上的std::vector.insert()(我的粗体字):

如果新的 size() 大于旧的,则导致重新分配 容量()。如果新的 size() 大于 capacity(),all 迭代器和引用无效。否则,只有 插入点之前的迭代器和引用仍然有效。这 过去的迭代器也失效了。

【讨论】:

it = vals.insert(it,100); // 修复它

以上是关于C++ 双重释放或损坏(出)的主要内容,如果未能解决你的问题,请参考以下文章

为啥使用 realloc() 时会出现双重释放或损坏错误?

MySQL 重启使用 MySQL C API 导致双重释放或损坏

使用 memset 和 freeaddrinfo 会导致双重释放或损坏错误

PHP 退出并出现“双重释放或损坏”错误

检测到 glibc - 在 C 程序中释放(int ** 类型)时出现双重释放或损坏消息

我的析构函数是不是给了我这个错误:*** `./main' 中的错误:双重释放或损坏(fasttop):?