首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在C++ STL中使用set的擦除属性后以几乎相同的方式获得不同的输出

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

Stack Overflow用户
提问于 2017-03-22 13:39:11
回答 1查看 61关注 0票数 2

在使用c++中的set时,我编写了以下code.It,只将元素从1推入到50,然后将元素推入s1和s2两个集合,然后从相同的值迭代到打印值,直到有固定的限制。但是,我无法理解为什么要为s1和s2获得不同的输出,因为惟一的区别是s1。擦除(it++)被写为{s2.erase(it);it++;}。

代码语言:javascript
复制
#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;
  }

产出如下:

代码语言:javascript
复制
 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
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-03-22 13:41:01

代码语言:javascript
复制
s2.erase(it);
it++;

很简单。这是违法的。一旦有了erased节点,就不允许使用迭代器,甚至不允许增加迭代器。你有https://en.wikipedia.org/wiki/Undefined_behavior

不明确的行为是一件讨厌的事情。您的代码可能崩溃,做一些奇怪的事情,甚至看起来正常工作。最后一种情况是最糟糕的,因为它可能会在未来某个未知的时刻破裂。

尽管语言本身并没有定义细节,但实际的原因是这是作为二叉树(红色-黑色树)实现的,因此每个节点都包含指向其左、右子节点的指针,并且可能包含它的父节点。这些指针用于在树中移动。一旦节点被删除,您就不可能期望它在检查这些指针时工作。

在另一种情况下:s1.erase(it++);在迭代器运行erase之前增加迭代器,这样您就可以愉快地继续查看容器的其余部分。

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

迭代器失效规则对于不同类型的容器是不同的,因此请确保仔细地使用阅读文件。(请注意,这不是真正的正式文档,只有标准,但这个网站非常受欢迎)。

我还建议您包括实际使用的标准标头 (例如<set>)和using namespace std;

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42953328

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档