为啥删除列表的 _first_ 元素会使 `.rend()` 无效?

     2023-02-22     137

关键词:

【中文标题】为啥删除列表的 _first_ 元素会使 `.rend()` 无效?【英文标题】:Why does removing the _first_ element of a list invalidate `.rend()`?为什么删除列表的 _first_ 元素会使 `.rend()` 无效? 【发布时间】:2013-02-07 20:13:19 【问题描述】:

使用 XCode 4.6 在 Mac OS X 上测试。

此示例代码显示删除 std::list 的最后一个元素按我的预期工作:对 list::end() 的迭代器引用仍然是“结束后 1”并且仍然有效,即使通过删除的最后一个元素

但第二个例子与我的直觉相反。删除列表的 first 元素更改list::rend(),我认为这是“1 过去的开头”。

我的预期错了吗?为什么错了?为什么通过删除最后一个元素对“结束后的 1”的引用仍然有效(不应该吗?),但在删除前面的元素后对“开始前的 1”(.rend())的引用变得无效?

void printList( list<int>& os )

  for( int& i : os )
    printf( "%d ", i ) ;
  puts("");


void testList()

  list< int > os ;
  os.push_back( 1 ) ;
  os.push_back( 2 ) ;
  os.push_back( 3 ) ;
  os.push_back( 4 ) ;
  os.push_back( 5 ) ;  

  // Forward iterators:  reference to .end() not invalidated when remove last elt.
  list<int>::iterator fwdEnd = os.end() ;
  printList( os ) ;
  os.erase( --os.end() ) ; // remove the 5 (last elt)
  printList( os ) ;
  if( fwdEnd == os.end() )  puts( "YES, fwdEnd==os.end() still, iterators not invalidated" ) ;  // I get __this__ result
  else puts( "NO: fwdEnd INVALIDATED" ) ;



  list<int>::reverse_iterator revEnd = os.rend() ;
  // remove the front element
  printList( os ) ;
  os.erase( os.begin() ) ; // removes the 1
  printList( os ) ;
  if( revEnd == os.rend() )  puts( "YES revEnd is still valid" ) ;
  else  puts( "NO: revEnd NOT valid" ) ; // I get __this__ result

【问题讨论】:

按照我的理解,反向迭代器并不指向它看似指向的东西。 “一个过去的开头”反向迭代器包装了一个引用开头的普通插入器。当包装的迭代器失效时,反向迭代器也是如此。但我没有引用标准来支持这一点。 我猜另一个问题是:rbegin 在第一个示例中是否同样无效?” 【参考方案1】:

这是因为反向迭代器的引用逻辑与常规迭代器略有不同:它指向一个元素,但在取消引用时,它会产生对前一个元素的引用。

如果您尝试以下操作,您将很容易看到这一点:

#include <vector>
#include <iostream>
#include <algorithm>

using namespace std;

int main()

    vector<int> v =  1, 2, 3, 4, 5, 6 ;
    auto i = find(begin(v), end(v), 3);
    cout << *i << endl;

    vector<int>::const_reverse_iterator ri(i);
    cout << *ri << endl;

输出应该是:

3
2

当反向迭代器物理上指向某个元素时,它逻辑上指向它之前的元素。因此,在物理上指向索引为 i 的集合中元素的反向迭代器在取消引用时会产生(引用)索引为 i-1 的元素:

                       i, *i
                       |
    -      1     2     3     4     5     6     -
                 |     | 
                 *ri   ri

这就是为什么 rend() 返回的迭代器实际上指向集合中的第一个元素,而不是第一个元素之前的元素。因此,删除第一个元素会使其无效。

           begin, *begin                       end, *end
           |                                   |
    -      1     2     3     4     5     6     -
    |      |                             |     |
*rend      rend                    *rbegin     rbegin

这不仅适用于列表,还适用于所有提供双向迭代器的集合。

【讨论】:

所以 没有真正的元素 称为“开头前面的 1”.. 而正向迭代器实际上指向“结束后的 1”,反向迭代器只是指向开头,取消引用时,指向“开头前面的 1” @bobobobo:我想有人可以这么说,尽管从技术上讲,甚至没有一个“在末尾称为 1 的元素”:迭代器只返回一个 position by end() 指向的,就是最后一个元素位置之后的位置。但我想这毕竟是你想说的,在这种情况下你是对的,rend() 返回的迭代器物理上没有指向“集合开始之前的位置”。

java示例代码_删除列表中的特定元素

java示例代码_删除列表中的特定元素 查看详情

java示例代码_算法——如何高效地删除列表中的重复元素

java示例代码_算法——如何高效地删除列表中的重复元素 查看详情

为啥 subselect 会使 SQL 请求变慢?

】为啥subselect会使SQL请求变慢?【英文标题】:WhysubselectmakestheSQL-requestslower?为什么subselect会使SQL请求变慢?【发布时间】:2014-08-2711:15:48【问题描述】:我有以下代码:select*fromtable_1jointable_2ontable_1.col1=table_2.col1wheretable_2.col2=1... 查看详情

redis_命令操作_list与redis_命令操作_set&sortedset

...  lrangekeystartend:范围获取           3.删除:              lpopkey:删除列表最左边的元素,并将元素返回                rpopkey:删除列表最右边的元素,并将元... 查看详情

python基础笔记-4python删除两个列表中相同的元素(代码片段)

删除两个列表中相同的元素Tips:1、被遍历的列表不可以直接做删除元素操作,不然列表本身长度变化会影响循环体执行结果。2、列表本身可能存在相同元素,考虑引入一个新的空列表存储相同元素,再执行一次循环来删除1、... 查看详情

java示例代码_从java中删除元素。util。列表

java示例代码_从java中删除元素。util。列表 查看详情

为啥在已删除的默认 ctor 旁边定义一个空的副本 ctor 会使空列表的值初始化失败?

】为啥在已删除的默认ctor旁边定义一个空的副本ctor会使空列表的值初始化失败?【英文标题】:Whydoesdefininganemptycopyctorbesideadeleteddefaultctormakeavalueinitializationwithemptylistfail?为什么在已删除的默认ctor旁边定义一个空的副本ctor会使... 查看详情

r语言_list()函数用法

...名称来访问。继续使用在上面例子的列表我们可以添加,删除和更新列表中的元素,如下图所示。我们可以增加或删除而且只能添加到列表的末尾的元素。但是可以更新任何元素。可以把所有的列表传到一个list()函数合并多个列... 查看详情

复合数据类型,英文词频统计(代码片段)

...,list)list.append(‘3658‘)print("增加元素:",list)  列表_删除:list=[‘a‘,‘b‘,5564,‘c‘]print("原始列表:",list)dellist[2]print("删除第三个元素:",list) 列表_修改list=[‘a‘,‘b‘,5564,‘c‘]print("原始列表:",list)list[2]=‘d‘print("修... 查看详情

如何获取对象的方法和属性的完整列表? [复制]

】如何获取对象的方法和属性的完整列表?[复制]【英文标题】:Howtogetacompletelistofobject\'smethodsandattributes?[duplicate]【发布时间】:2010-09-1612:02:39【问题描述】:dir(re.compile(pattern))不返回模式作为列表的元素之一。即它返回:[\'__c... 查看详情

python列表删除会出现一个错误listindexoutofrange

1,这是列表在删除的时候出现的一个问题,目的是为了删除列表中的0元素#_*_coding:utf-8_*_#__author__='dragon'P=[0,1,2,2,2,1,0,0,0,0,0,0,0,1,0,2,0,1,0,44,1,0]foriinrange(0,len(P)-1):if(P[i]==0):delP[ 查看详情

为啥有些前面带“__”的方法不是私有的? [复制]

】为啥有些前面带“__”的方法不是私有的?[复制]【英文标题】:Whyaresomemethodswith"__"infrontofthemnotprivate?[duplicate]为什么有些前面带“__”的方法不是私有的?[复制]【发布时间】:2020-07-3115:14:58【问题描述】:据我所知,... 查看详情

基本数据类型____元组

...元组进行组合,也就是运算,类似于字符串的拼接元组的删除:元组中的元素是不允许删除的,但是我们却可以删除整 查看详情

为啥列表有 __reverse__() 特殊方法但元组在 Python 中没有?

】为啥列表有__reverse__()特殊方法但元组在Python中没有?【英文标题】:Whydolistshavea__reverse__()specialmethodbuttuplesdon\'tinPython?为什么列表有__reverse__()特殊方法但元组在Python中没有?【发布时间】:2016-09-2010:23:35【问题描述】:Python... 查看详情

golangbasic_leaming2语言容器(代码片段)

...语言遍历数组参考文献Go语言切片(Slice)初始化_删除元素_遍历什么是切片声明切片使用make()函数构造切片使用append()函数为切片添加元素从数组或切片生成新的切片从指定范围中生成切片重置切片复制切片元素到另一个... 查看详情

基本数据类型____元组

...元组进行组合,也就是运算,类似于字符串的拼接元组的删除:元组中的元素是不允许删除的,但是我们却可以删 查看详情

根据条件删除列表元素

】根据条件删除列表元素【英文标题】:Deletinglistelementsbasedoncondition【发布时间】:2011-11-2905:42:34【问题描述】:我有一个列表列表:[word,goodfreq,badfreq,change_status]list_1=[[\'good\',100,20,0.2],[\'bad\',10,0,0.0],[\'change\',1,2,2]]我想从列表中... 查看详情

为啥我不能删除 _mm_empty()?

】为啥我不能删除_mm_empty()?【英文标题】:Whycan\'tIremove_mm_empty()?为什么我不能删除_mm_empty()?【发布时间】:2015-12-1609:25:31【问题描述】:我有一个带有一些SSE2指令的c++函数。问题是我在使用microsoftvisualc++编译此代码时收到以... 查看详情