在几乎相同的方式使用C++ STL中的set属性后获得不同的输出

nir*_*van 2 c++ stl set

在c ++中使用set时,我编写了以下代码.它只是将元素从1到50推送到两个集合s1和s2,然后对于这两个集合,我从相同的值迭代到打印值直到固定限制.但我无法理解为什么我得到s1和s2的不同输出,因为唯一的区别是s1.erase(it ++)写成{s2.erase(it); it ++;}.

#include<bits/stdc++.h>
using namespace std;
set<int> s1,s2;
int main()
{
    int l,r,i;
    for(i=1;i<=50;i++)
    {       s1.insert(i);
            s2.insert(i);
    }
    //scanf("%d%d",&l,&r);
    l=3;r=9;

    printf("Output 1:\n");
    set<int>::iterator it=s1.lower_bound(l);

    while(it!=s1.end() && (*it<=r))
    {
            printf("Before deletion: %d\n",*it);
            s1.erase(it++);
            printf("After deletion: %d\n",*it);
    }

    it=s2.lower_bound(l);
    printf("Output 2\n");
    while(it!=s2.end() && (*it<=r))
    {
            printf("Before deletion: %d\n",*it);
            s2.erase(it);
            it++;
            printf("After deletion: %d\n",*it);
    }
    return 0;
  }
Run Code Online (Sandbox Code Playgroud)

输出是:

 Output 1:
Before deletion: 3
After deletion: 4  
Before deletion: 4
After deletion: 5
Before deletion: 5
After deletion: 6
Before deletion: 6
After deletion: 7
Before deletion: 7
After deletion: 8
Before deletion: 8 
After deletion: 9
Before deletion: 9
After deletion: 10
Output 2
Before deletion: 3
After deletion: 2
Before deletion: 2
After deletion: 4
Before deletion: 4
After deletion: 6
Before deletion: 6
After deletion: 7
Before deletion: 7
After deletion: 5
Before deletion: 5
After deletion: 8
Before deletion: 8
After deletion: 10
Run Code Online (Sandbox Code Playgroud)

BoB*_*ish 5

s2.erase(it);
it++;
Run Code Online (Sandbox Code Playgroud)

简单.这是非法的.一旦有了erase该节点,就不允许使用迭代器,甚至可以增加它.您有未定义的行为.

未定义的行为是令人讨厌的事情.您的代码可能崩溃,做一些奇怪的事情,甚至看起来工作正常.最后一种情况是最糟糕的,因为它可能会在未来的某个未知点突破.

虽然语言本身没有定义细节,但实际的原因是它实现为二叉树(红黑树),因此每个节点都包含指向其左右子节点以及可能是其父节点的指针.这些指针用于在树中移动.删除节点后,在检查这些指针时,您不可能期望它能够正常工作.

在另一种情况下:之前s1.erase(it++);递增迭代器,这样你就可以继续查看容器的其余部分了. erase

另一种可能性是it = s2.erase(it);,因为erase返回下一个迭代器(注意这可能是end()).这是一种更常见/惯用的模式,并且应该仅仅因为这个原因而首选,但它也适用于其他容器类型(您的版本不适用).

迭代器失效规则对于不同类型的容器是不同的,因此请务必仔细阅读文档.(注意这不是真正的官方文档,只有标准,但这个网站很受欢迎).


我还建议你包括你实际使用的标准头文件(例如<set>),并避免使用using namespace std;.

  • 它应该是`it = s2.erase(it);`请添加一个指向docs的链接:http://en.cppreference.com/w/cpp/container/set/erase (2认同)