_reverse_iterator实现及理解

本文详细探讨了C++中list容器的迭代器失效问题,特别是在删除元素时的情况。在list中,删除元素会导致相应迭代器失效,但其他迭代器不受影响。同时,介绍了如何修正迭代器在删除元素后的失效问题。此外,还讲解了list的反向迭代器实现原理。最后,对比了list与vector在内存结构、插入删除效率和空间利用率等方面的差异,以帮助开发者选择合适的容器。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

list 的迭代器失效
前面说过,此处大家可将迭代器暂时理解成类似于指针, 迭代器失效即迭代器所指向的节点的无效,即该节 点被删除了 。因为 list 的底层结构为带头结点的双向循环链表 ,因此 list 中进行插入时是不会导致 list 的迭代 器失效的,只有在删除时才会失效,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响
void TestListIterator1 ()
{
int array [] = { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 0 };
list < int > l ( array , array + sizeof ( array ) / sizeof ( array [ 0 ]));
auto it = l . begin ();
while ( it != l . end ())
{
// erase() 函数执行后, it 所指向的节点已被删除,因此 it 无效,在下一次使用 it 时,必须先给
其赋值
l . erase ( it );
++ it ;
}
}
// 改正
void TestListIterator ()
{
int array [] = { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 0 };
list < int > l ( array , array + sizeof ( array ) / sizeof ( array [ 0 ]));
auto it = l . begin ();
while ( it != l . end ())
{
l . erase ( it ++ ); // it = l.erase(it);
}
}
list 的反向迭代器
通过前面例子知道,反向迭代器的 ++ 就是正向迭代器的 -- ,反向迭代器的 -- 就是正向迭代器的 ++,因此反向迭代器的实现可以借助正向迭代器,即:反向迭代器内部可以包含一个正向迭代器,对正向迭代器的接口进行包装即可。
template < class Iterator >
class ReverseListIterator
{
// 注意:此处 typename 的作用是明确告诉编译器, Ref Iterator 类中的类型,而不是静态成员变量
// 否则编译器编译时就不知道 Ref Iterator 中的类型还是静态成员变量
// 因为静态成员变量也是按照 类名 :: 静态成员变量名 的方式访问的
public :
typedef typename Iterator::Ref Ref ;
typedef typename Iterator::Ptr Ptr ;
typedef ReverseListIterator < Iterator > Self ;
public :
//
// 构造
ReverseListIterator ( Iterator it ): _it ( it ){}
//
// 具有指针类似行为
Ref operator * (){
Iterator temp ( _it );
-- temp ;
return * temp ;
}
Ptr operator -> (){ return & ( operator * ());}
//
// 迭代器支持移动
Self & operator ++ (){
-- _it ;
return * this ;
}
Self operator ++ ( int ){
Self temp ( * this );
-- _it ;
return temp ;
}
Self & operator -- (){
++ _it ;
return * this ;
}
Self operator -- ( int )
{
Self temp ( * this );
++ _it ;
return temp ;
}
//
// 迭代器支持比较
bool operator != ( const Self & l ) const { return _it != l . _it ;}
bool operator == ( const Self & l ) const { return _it != l . _it ;}
Iterator _it ;
};
list vector 的对比
vector list 都是 STL 中非常重要的序列式容器,由于两个容器的底层结构不同,导致其特性以及应用场景不同,其主要不同如下
                       vector                                                   list
层                   
               动态顺序表,一段连续空间                 带头结点的双向循环链表
 
                                                               
机    支持随机访问,访问某个元素效率O(1)      不支持随机访问,访问某个元素
                                                                          效率 O(N)
访
入      
              任意位置插入和删除效率低,需          
和          要搬移元素,时间复杂 度为 O(N) ,    任意位置插入和删除效率高,不
              插入时有可能需要增容,增容:         需要搬移元素,时间复杂度为
删          开辟新空 间,拷贝元素,释放            O(1)
除           旧空间,导致效率更低
             
         
           
间       底层为连续空间,不容易造成内存碎片,   底层节点动态开辟,小节点容易
利       空间利用率高,缓存利用率高                      造成内存碎片,空间利用率低,
用                                                                             缓存利用率低
代                          原生态指针                             对原生态指针 ( 节点指针 ) 进行封装
代  在插入元素时,要给所有的迭代器重新赋值,           插入元素不会导致迭代器失效,
器  因为插入元素有可能会导致重新扩容,致使原           删除元素时,只会导致当前迭代
失  来迭代器失效,删除时,当前迭代器需要重新            器失效,其他迭代器不受影响
效  赋值否则会失效
使
用        需要高效存储,支持随机访问,不关                  大量插入和删除操作,不关心随
场        心插入删除效率                                                   机访问
Line 7: Char 9: ================================================================= ==22==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x502000000354 at pc 0x55de9091eda9 bp 0x7ffeb85c4260 sp 0x7ffeb85c4258 READ of size 4 at 0x502000000354 thread T0 #0 0x55de9091eda8 in swap<int> /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/bits/move.h:222:13 #1 0x55de9091eda8 in iter_swap<__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > >, __gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > > > /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/bits/stl_algobase.h:185:7 #2 0x55de9091eda8 in void std::__reverse<__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int>>>>(__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int>>>, __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int>>>, std::random_access_iterator_tag) /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/bits/stl_algo.h:1062:4 #3 0x55de9091ec00 in reverse<__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > > > /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/bits/stl_algo.h:1089:7 #4 0x55de9091ec00 in Solution::rotate(std::vector<int, std::allocator<int>>&, int) solution.cpp:7:9 #5 0x55de9091e4ad in __helper__ solution.cpp:7:18 #6 0x55de9091e4ad in main solution.cpp:7:30 #7 0x7f3b1408a1c9 (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6) #8 0x7f3b1408a28a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6) #9 0x55de90847f44 in _start (solution+0xb2f44) 0x502000000354 is located 0 bytes after 4-byte region [0x502000000350,0x502000000354) allocated by thread T0 here: #0 0x55de9091bb6d in operator new(unsigned long) /root/llvm-project/compiler-rt/lib/asan/asan_new_delete.cpp:86:3 #1 0x55de909381de i
03-09
### 解决C++ AddressSanitizer检测到的堆缓冲区溢出问题 当遇到由`AddressSanitizer`报告的`heap-buffer-overflow`错误时,这通常意味着程序尝试访问超出分配给对象的有效范围之外的内存位置。对于涉及`swap`, `reverse`, 或者`rotate`函数操作的标准库容器(如`vector`),此类错误可能源于不正确的索引计算、迭代器失效或者传递给这些算法的数据结构处于未定义状态。 为了防止这种类型的越界访问,在调用上述任何一种标准库算法之前,应该确保: 1. **验证输入参数**:确认传入容器或数组边界内的所有指针和下标都是有效的,并且不会导致读取或写入非法地址。 2. **检查容量与大小的区别**:理解并区分`capacity()` 和 `size()`. 尤其是在动态调整向量尺寸的情况下,应始终基于当前元素数量(`size`)而不是预留空间(`capacity`)来执行逻辑判断[^1]. 3. **避免悬空引用**:如果在多线程环境中共享数据,则需特别注意同步机制以保护共同资源免受竞态条件影响;即使在同一上下文中也应当小心处理临时变量生命周期管理不当所造成的潜在风险. 4. **利用现代特性简化代码**:采用lambda表达式可以减少命名函数带来的复杂度以及由此引发的一系列问题。例如,在自定义比较器中使用匿名函数能够有效降低因外部依赖而产生的副作用概率[^2]. 针对具体场景中的`swap`, `reverse`, 或者`rotate`方法应用以上原则可以帮助消除可能导致`heap-buffer-overflow` 的隐患。此外,建议启用编译器警告选项(-Wall -Wextra),并通过静态分析工具进一步审查源码质量。 ```cpp #include <algorithm> #include <iostream> #include <vector> void safe_reverse(std::vector<int>& vec) { if (!vec.empty()) { // Ensure the vector has elements before reversing. std::reverse(vec.begin(), vec.end()); } } // Example usage with lambda expression for custom sorting criteria bool compare_weights(int x, int y) { return /* some condition */; } int main(){ std::vector<int> numbers{5, 3, 8}; auto comp = [](int x, int y){return (/*some logic*/)}; std::sort(numbers.begin(),numbers.end(),comp); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值