unexpend for-loop result after change the third part of for-loop

落花浮王杯 提交于 2021-01-29 04:59:37

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!