如何获得列表中的倒数第二个元素?


69

我有一个 std::list<double> foo;

我正在使用

if (foo.size() >= 2){
    double penultimate = *(--foo.rbegin());
}

但这总是给我一个任意值penultimate

我究竟做错了什么?


25
最后,一个新用户写的很好的问题。有一个赞!
拔示巴

29
对于像我这样的人,他们不记得“倒数第二个”意味着什么,它意味着倒数第二个
Justin

1
@Mehrdad OP绝对不想要那样。特别是因为该迭代器没有指向任何元素。
Marc van Leeuwen

1
除非您知道您特别需要一个链表并且可以清楚说明原因,否则请不要使用std::list。更喜欢std::vector
罗布·K

Answers:


67

而不是减少 rbegin,您应该增加它,如下所示:1

double penultimate = *++foo.rbegin();

asrbegin()返回反向迭代器++操作员也将在容器中向后移动。请注意,我也删除了多余的括号:这并不符合每个人的口味。

当前,您的程序的行为是不确定的,因为您实际上是在迁移到end(),因此您不能取消引用它。输出的任意性质是这种不确定行为的体现。


1确保保留当前的最小尺寸检查。


无论如何,为什么仍可以将operator ++应用于临时右值?我以为++,-等仅适用于左值

@cat对于允许它的迭代器,operator++通常至少是我所知的成员函数。没有规则说明成员函数只能在左值上调用,除非成员函数被ref限定为&
贾斯汀时间-恢复莫妮卡

OP并没有移到foo.end()哪一个是完全有效的迭代器(尽管无法取消引用),而是foo.rbegin()-1无效的,甚至在尝试取消引用之前也是如此。
Marc van Leeuwen

27

在我看来,最清晰的方法是使用为此目的而设计的构造(C ++ 11):

double penultimate = *std::prev(foo.end(), 2)

仅当您掌握了C ++ 11中添加的所有功能时才清除,并且如果您想使代码向后不兼容,则是个好主意;)我什至不知道它的std::prev存在!
user541686

在我看来,这绝对是最清晰的解决方案,因为它涉及最少的操作员呼叫,并且避免了已接受答案的向后/向前混淆。
接近

4
C ++ 11于6年前问世。如果用户希望使用传统方法,则应提出要求。
格雷戈里·柯里

11

我会做的*--(--foo.end()); 无需反向迭代器。它也减少了混乱。


3
如果您想知道(就像我一样),则由于最终迭代器指向虚构的过去到结束元素而减少了两个。
安德烈亚斯(Andreas)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.