Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::map erase - pass iterator to wrong map

Take this snippet of C++:

#include <map>

int main() {
    std::map<int, int> m1;
    m1[1] = 2;

    std::map<int, int> m2;
    m2[3] = 4;
    m1.erase(m2.begin());

    return m2.size();
}

On godbolt: https://godbolt.org/z/mJBszn

This feels like it must be undefined behaviour. Is that correct? If so, which part of the standard says so?

like image 476
Drew Avatar asked Mar 15 '26 14:03

Drew


2 Answers

This feels like it must be undefined behaviour. Is that correct?

Yes.

If so, which part of the standard says so?

The standard slaps down this bit of silliness in [associative.reqmts] note 8. I am citing n4659 because it's what I have a link to and close to C++17. At this time C++20 is still too much of a moving target.

Diving down into [tab:container.assoc.req] we find three erase overloads that take iterators,

a.erase(q)
a.erase(r)
a.erase(q1, q2)

of which a.erase(r) is the one of interest to the asker.

The table only states what happens if the program behaves; however the preamble to this table states that

q denotes a valid dereferenceable constant iterator to a, r denotes a valid dereferenceable iterator to a, [q1, q2) denotes a valid range of constant iterators in a

In other words, if the iterator r is not from map a, a's end iterator, or has been invalidated or otherwise rendered undereferenceable, the contract is broken and the results have been left undefined.

I include q, q1 and q2 to show the rules are the same for a constant iterator and iterator ranges.

like image 159
user4581301 Avatar answered Mar 17 '26 04:03

user4581301


This is all in reference to C++17.

Edit 2** I take back what I originally said, I just thread through part of the c++ standard and from a comment. In §26.2.6 the standard states for a.erase(r) in the context of associative containers is "If no such element exists, returns a.end()." However, the standard also states "r denotes a valid dereferenceable iterator to a"

Since this is not the case for m2.begin(), this is not in line with the standard, thus undefined behavior.

like image 28
BTables Avatar answered Mar 17 '26 04:03

BTables



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!