检测迭代器是否为std::map的最后一个元素

10

这与此问题类似,但不是重复的。我正在尝试迭代地遍历一个map并打印每个元素的值,但在最后一个元素上输出略有不同。在那个问题中,他们建议使用map.rbegin().base(),但对我来说它没有起作用。

以下是我的代码:

#include <iostream>
#include <map>

int main()
{
    std::map <char, int> charMap = { {'a', 1}, {'b', 2}, {'c', 3}, {'d', 4} };
    for (auto iter = charMap.begin(); iter != charMap.end(); iter++)
    {
        std::cout << iter->first << ":\t" << iter->second;
        if (iter == charMap.rbegin().base())
            std::cout << "\t//This is the last element.\n";
        else
            std::cout << "\n";
    }
}

我期望输出结果如下所示:
a:    1
b:    2
c:    3
d:    4    //This is the last element. 

但是,实际上我得到的输出是:
a:    1
b:    2
c:    3
d:    4    

现在我意识到有一种更好的方法来解决这个问题,但我认为这种方法也应该可行。为什么我不能比较itercharMap.rbegin().base()

请注意,在这种情况下,通常很容易重写循环体,使得特殊处理发生在第一个元素而不是最后一个元素。 - Christian Hackl
1
@ChristianHackl 注意,显然这里不是这种情况 :) - BartoszKP
1
@BartoszKP:为什么不呢?每一行都以换行符开头,除了第一行,将“这是最后一个元素”放在循环之后。 - Christian Hackl
1
@ChristianHackl 您说得对,但是OP已经意识到了这一点,问题特别针对当前的流程。 - BartoszKP
7个回答

17

使用来自<iterator>std::next作为

if (std::next(iter) == charMap.end())
    std::cout << "\t//This is the last element.\n";

替代方案。


哦,我之前使用了一个单独的迭代器然后对它进行递增。很高兴知道std::next()的存在。 - DJMcMayhem
有效自 C++11 - matteolel
1
最好使用反向迭代器来检查元素是否为最后一个,因为反向迭代器的逻辑比较奇怪。这解决了我在std::vector上的问题。 - sergiol

5

base() 方法返回一个迭代器,该迭代器指向被反向迭代器所指向的元素之后的元素。这意味着 rbegin().base() 等同于 end()

为了完成您的任务,您可以这样做:

#include <iostream>
#include <map>

int main()
{
    std::map <char, int> charMap = { {'a', 1}, {'b', 2}, {'c', 3}, {'d', 4} };
    for (auto iter = charMap.begin(); iter != charMap.end(); )
    {
        std::cout << iter->first << ":\t" << iter->second;
        if (++iter == charMap.end())
            std::cout << "\t//This is the last element.\n";
        else
            std::cout << "\n";
    }
}

4
因为 std::reverse_iterator 存储了偏移量为 1 的迭代器,所以 charMap.rbegin().base() == charMap.end()。可以在此处查看示意图 here
因此,您应该使用 <iterator> 中的 std::prevstd::next
iter == std::prev(charMap.end())

或者

std::next(iter) == charMap.end()

无论你觉得哪个更有意义。

2

base()不返回相同的元素:

基础迭代器指向下一个(从std::reverse_iterator::iterator_type的角度)当前reverse_iterator所指向的元素。也就是说,&*(rit.base() - 1) == &*rit

这个功能可以正常工作:

#include <iostream>
#include <map>

int main()
{
    std::map <char, int> charMap = { {'a', 1}, {'b', 2}, {'c', 3}, {'d', 4} };
    auto last = charMap.rbegin();
    ++last;

    for (auto iter = charMap.begin(); iter != charMap.end(); iter++)
    {
        std::cout << iter->first << ":\t" << iter->second;
        if (iter == last.base())
            std::cout << "\t//This is the last element.\n";
        else
            std::cout << "\n";
    }
}

1
实际上,这并不会起作用,因为iter确实与charMap.rbegin().base()不同。
你的逻辑是正确的,唯一的问题是charMap.rbegin().base()迭代器等于charMap.end(),但你在iter到达charMap.end()值时离开了for循环,所以它从未有机会在for循环内部的if语句中进行测试。
要使其工作,您可以按以下方式重写if语句:
if (iter->first == charMap.rbegin()->first)
    std::cout << "\t//This is the last element.\n";
else
    std::cout << "\n";

所以你将比较地图键而不是迭代器本身。

0

这个可以工作:

#include <iostream>
#include <map>

int main()
{
    std::map <char, int> charMap = { {'a', 1}, {'b', 2}, {'c', 3}, {'d', 4} };
    for (auto iter = charMap.begin(); ;)
    {
        std::cout << iter->first << ":\t" << iter->second;          
        if (++iter== charMap.end()){
            std::cout << "\t//This is the last element.\n"; break;
        }
        else
            std::cout << "\n";
    }

}

0

丑陋的……但是……

    auto iterCpy = iter;
    if (++iterCpy == charMap.end())
        std::cout << "\t//This is the last element.\n";

使用vsoftco的答案 :)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接