为什么set(c ++)中的迭代器行为不正常?

时间:2016-08-12 15:29:47

标签: c++ iterator set multiset

这是我写的代码:

multiset<int>S;
for(int i = 0;i<20;i++)
S.insert(i);
for(auto it = S.end();it!=S.begin();--it)
cout<<*it<<" ";
cout<<endl;

输出:

20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 

3 个答案:

答案 0 :(得分:2)

您的代码包含一些未定义的行为。正如您已经指出的那样,S将包含0到20之间的所有值(不包括),但不知何故打印给出1到20(包括)。

您的代码:

for(auto it = S.end();it!=S.begin();--it)
    cout<<*it<<" ";

这里的问题是范围[begin, end)end指的是不属于集合的东西。取消引用从end()接收的迭代器可能会使程序崩溃或让它产生一些随机值。在这种情况下,我猜你因为编译器优化而得到值20。 (一些黑盒优化)

在C ++(和其他语言)中,迭代器的概念伴随着reverse iterators的概念。 (如果你按照链接,有一个很好的图片解释迭代器。)

基本上,使用反向迭代器将允许您从后面循环到开头,就像使用普通迭代器循环一样:

for (auto it = S.crbegin(); it != S.crend(); ++it)
     cout << *it << " ";

请注意,rbegin()和crbegin()对代码复杂性没有任何缺点。 (除非你想再将它们转换为前向迭代器)

Bonus:默认情况下,不要在迭代器上使用 - 运算符,在尝试调试时会让人头疼。

答案 1 :(得分:1)

使用迭代器的循环不正确并且具有未定义的行为,因为成员函数end()返回的迭代器在循环中被取消引用。

有效的程序可能看起来像

#include <iostream>
#include <set>

int main() 
{
    std::multiset<int> s;

    for ( int i = 0; i < 20; i++ ) s.insert( i );

    for ( auto it = s.end(); it != s.begin(); ) std::cout << *--it << " ";
    std::cout << std::endl;

    return 0;
}

它的输出是

19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 

当然,您可以使用函数rbegin()返回的类的反向迭代器。例如

#include <iostream>
#include <set>

int main() 
{
    std::multiset<int> s;

    for ( int i = 0; i < 20; i++ ) s.insert( i );

    for ( auto it = s.rbegin(); it != s.rend(); ++it ) std::cout << *it << " ";
    std::cout << std::endl;

    return 0;
}

在这种情况下,循环看起来更简单。

答案 2 :(得分:-2)

更好用:

for(auto it = S.rbegin(); it != S.rend(); ++it)

根据评论更新。