在基于迭代器的循环中增长一个向量,在用munmap_chunk()反编译时崩溃:无效指针,为什么?

问题描述 投票:0回答:1

谁能解释一下为什么我的程序在使用基于迭代器的for循环时崩溃,而在使用基于索引的for循环时不崩溃?我怀疑是因为基于索引的 for() 每次都会被评估,而基于迭代器的 for() 语句不知为何不是。

我试图在一个向量上循环,当到达最后一个元素并且是我要找的元素时,调整向量的大小,然后再添加一个元素。如果我使用的是 push_backresize.

这是玩具代码,作为一个例子,一个学习经验。我想知道为什么一个会崩溃,另一个不会。

下面的代码在调用向量的析构器时出现错误,导致崩溃 munmap_chunk(): invalid pointer:

#include <iostream>
#include <vector>

int main() {
    std::vector<int> exampleVector {0,1,2,3,4,5};
    // iterator based loop
    for (auto it = exampleVector.begin(); it != exampleVector.end(); ++it) {
        if (*it == 5 && std::next(it) == exampleVector.end()) {
            exampleVector.resize(exampleVector.size() + 1);
            *std::next(it) = 999;
            *it = 0;
        }
    }
    return 0;
}

从Clion调试窗口复制的堆栈。

__GI_raise 0x00007f8cd892ce97
__GI_abort 0x00007f8cd892e801
__libc_message 0x00007f8cd8977897
malloc_printerr 0x00007f8cd897e90a
munmap_chunk 0x00007f8cd8985ecc
__GI___libc_free 0x00007f8cd8985ecc
__gnu_cxx::new_allocator<int>::deallocate new_allocator.h:125
std::allocator_traits<std::allocator<int> >::deallocate alloc_traits.h:462
std::_Vector_base<int, std::allocator<int> >::_M_deallocate stl_vector.h:180
std::_Vector_base<int, std::allocator<int> >::~_Vector_base stl_vector.h:162
std::vector<int, std::allocator<int> >::~vector stl_vector.h:435
main main.cpp:5
__libc_start_main 0x00007f8cd890fb97
_start 0x000055f736f6aaca

这个程序没有。

#includee <iostream>
#include <vector>

int main() {
    std::vector<int> exampleVector {0,1,2,3,4,5};
    // indexed for loop
    for (size_t i = 0; i < exampleVector.size(); ++i) {
        if (exampleVector.at(i) == 5 and exampleVector.at(i) == exampleVector.back()) {
            exampleVector.resize(exampleVector.size() + 1);
            exampleVector.at(i + 1) = 999;
            exampleVector.at(i) = 0;
        }
    }

    return 0;
}

在Ubuntu 18.04中,当你进行以下操作时,会得到默认的gcc版本: apt install build-essential.

再次,寻找为什么一个崩溃而另一个不崩溃的原因。另外,这适用于基于范围的for循环吗?

c++
1个回答
2
投票

当你调整一个 std::vector,指向它的迭代器可能会失效。所以你需要重置 it 调整大小后。

if (*it == 5 && std::next(it) == exampleVector.end()) {
     exampleVector.resize(exampleVector.size() + 1);
     it = std::next(exampleVector.begin(), exampleVector.size() - 2);
     // ...
}

很明显,索引只是 ints,所以不存在关于它们变得无效的问题,所以你的第二个例子可以正常工作。

Range-for循环只是基于迭代器的循环的漂亮语法,所以是的,它会有和第一个版本一样的问题。

© www.soinside.com 2019 - 2024. All rights reserved.