简体   繁体   中英

C++ double free or corruption(out)

I came across this error when I was using iterators with vector STL.

Code:-

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

Output:-

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)

I do not understand why this is happening: is it an issue with the iterator after the vector is modified? I think that my intuition regarding iterators is flawed.

When a std::vector is resized, the iterator becomes invalid because it refers to the vector before resizing which may include moving the vector to a different memory location in order to maintain a contiguity. In that case it will not be automatically updated to refer to the new location.

The result in this case (because it is undefined behaviour) is that the value 200 was not inserted in the vector, but it was written to some other heap memory that the vector previously occupied that has since been deallocated - ie you corrupted the heap. The vector is destroyed on exit from main, and at that time the system heap management fails and the error is reported (after the fact).

Reassigning the iterator following the insertion resolves the issue:

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

The output of the single item reports 5 rather then 4 as you might expect because it is simply reading the old vector memory not yet reused and overwritten with something else.

You can observe the error by comparing:

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

with

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

Your results are likely to differ but at https://www.onlinegdb.com/ when I performed the test, the distance between the iterator position and the vector start in the first case was 16 - demonstrating that the iterator no longer refers to an element in the current vector state. In the second case the distance is zero - the iterator refers to the start of the new vector state.

If the capacity of vals were extended before taking the iterator by for example:

vals.reserve(10);

Then the insertion of a single element would not cause a mem-move, and the failure would not have occurred - that does not make it a good idea not to update the iterator though - it is merely to indicate what is happening under the hood.

...is it an issue with the iterator after the vector is modified?

Yes!

From the cppreference page on std::vector.insert() (bolding mine):

Causes reallocation if the new size() is greater than the old capacity(). If the new size() is greater than capacity(), all iterators and references are invalidated . Otherwise, only the iterators and references before the insertion point remain valid. The past-the-end iterator is also invalidated.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM