问题
When I use for-loop
in my source file, I get a unexpend result. Here is the minimum source file (I hide the head of file and the function of print_set
):
// the main function
int main(void) {
set<int> test{3, 5};
print_set(test);
for (auto it = test.begin(); it != test.end();) {
auto node = test.extract(it);
++it;
}
print_set(test);
}
Then I use command to compile and run:
$ g++ --version
g++ (Dedian 8.3.0-6) 8.3.0
... (not very important infomation for this question)
$ g++ -std=c++17 temp.cpp
$ ./a.out
[ 3 5 ]
[ ]
Now all thing goes well but after I change the for-loop
part to this (I replace ++it
to the third part of for-loop
's head):
for (auto it = test.begin(); it != test.end(); ++it) {
auto node = test.extract(it);
}
Now the result is:
$ ./a.out
[ 3 5 ]
zsh: segmentation fault (core dumped) ./a.out
Zsh
is the Linux shell that I am using that is not very important infomation. After view some web pages about for-loop
like this, etc., I still do not know why? Is it a bug? Why these are not equal and have two different results? Because the method extract
? But why can the first part can run?
Thanks.
回答1:
From the std::set<T>::extract() documentation:
Extracting a node invalidates the iterators to the extracted element.
After the call to test.extract(it)
, the iterator it
is no longer valid. Even incrementing it or comparing it to another iterator are not defined operations. The only safe things you can do to it
after extraction are:
- Let it be destructed.
- Assign a valid iterator to it.
Anything else causes undefined behavior, therefore both code examples in your question invoke undefined behavior. Asking why one does something different than the other is a meaningless question. They might each do something different each time the program is run -- including what you wanted the code to do!
Undefined behavior cannot be reasoned about and it is almost always a waste of time trying to do so.
To fix the code, you would need to copy the iterator, increment the original, then extract the copy. This is exactly what the post-increment operator does:
for (auto it = test.begin(); it != test.end();) {
auto node = test.extract(it++);
}
In this example, it
is mutated before extraction happens. This example has well-defined behavior, and will extract each element in the set one by one.
来源:https://stackoverflow.com/questions/62852144/unexpend-for-loop-result-after-change-the-third-part-of-for-loop