0

0

C++STL迭代器类型与用法详解

P粉602998670

P粉602998670

发布时间:2025-09-19 09:45:01

|

522人浏览过

|

来源于php中文网

原创

C++ STL迭代器是访问容器元素的通用方式,分为输入、输出、前向、双向和随机访问五种类型,分别适用于不同场景;通过begin()和end()获取迭代器,可遍历vector、list、map等容器;使用时需注意插入或删除导致的迭代器失效问题,尤其在vector中易发生;可通过自定义迭代器类并重载*、++、==等操作符实现灵活访问;迭代器还与算法如copy、transform、find结合使用,提升代码复用性和效率。

c++stl迭代器类型与用法详解

C++ STL 迭代器是访问容器中元素的通用方式,它类似于指针,但提供了更高级的功能和安全性。理解迭代器的类型和用法是掌握 STL 的关键。

迭代器类型与用法详解:

迭代器是连接算法和容器的桥梁。它允许我们以统一的方式访问不同类型容器中的元素,而无需关心容器底层的实现细节。

C++ STL 迭代器有哪些类型?

C++ STL 提供了五种主要的迭代器类型,每种类型都具有不同的功能和限制。了解这些类型有助于我们选择最适合特定任务的迭代器。

立即学习C++免费学习笔记(深入)”;

  1. 输入迭代器 (Input Iterator): 只读迭代器,只能单向移动,用于从容器中读取数据。只能读取一次,不能多次读取相同位置的值。例如,

    istream_iterator

  2. 输出迭代器 (Output Iterator): 只写迭代器,只能单向移动,用于向容器中写入数据。只能写入一次,不能多次写入相同位置的值。例如,

    ostream_iterator

  3. 前向迭代器 (Forward Iterator): 读写迭代器,可以单向移动,可以多次读取和写入相同位置的值。它具有输入迭代器和输出迭代器的所有功能。

  4. 双向迭代器 (Bidirectional Iterator): 读写迭代器,可以双向移动,可以多次读取和写入相同位置的值。它具有前向迭代器的所有功能,并增加了向后移动的能力。

    list
    ,
    set
    ,
    multiset
    ,
    map
    ,
    multimap
    等容器通常提供双向迭代器。

  5. 随机访问迭代器 (Random Access Iterator): 读写迭代器,可以随机访问容器中的任何元素,可以进行加减运算,比较大小等操作。它具有双向迭代器的所有功能,并增加了随机访问的能力。

    vector
    ,
    deque
    ,
    array
    等容器通常提供随机访问迭代器。

如何使用迭代器遍历容器?

使用迭代器遍历容器是 STL 中常见的操作。以下是一些示例,展示了如何使用不同类型的迭代器遍历不同类型的容器。

示例 1: 使用迭代器遍历

vector

#include 
#include 

int main() {
  std::vector vec = {1, 2, 3, 4, 5};

  // 使用迭代器遍历 vector
  for (std::vector::iterator it = vec.begin(); it != vec.end(); ++it) {
    std::cout << *it << " ";
  }
  std::cout << std::endl;

  // 使用 const_iterator 遍历 vector (只读)
  for (std::vector::const_iterator it = vec.cbegin(); it != vec.cend(); ++it) {
    std::cout << *it << " ";
  }
  std::cout << std::endl;

  // 使用 auto 关键字简化迭代器声明 (C++11 及以上)
  for (auto it = vec.begin(); it != vec.end(); ++it) {
    std::cout << *it << " ";
  }
  std::cout << std::endl;

  // 使用范围 for 循环 (C++11 及以上)
  for (int element : vec) {
    std::cout << element << " ";
  }
  std::cout << std::endl;

  return 0;
}

示例 2: 使用迭代器遍历

list

#include 
#include 

int main() {
  std::list lst = {1, 2, 3, 4, 5};

  // 使用迭代器遍历 list
  for (std::list::iterator it = lst.begin(); it != lst.end(); ++it) {
    std::cout << *it << " ";
  }
  std::cout << std::endl;

  return 0;
}

示例 3: 使用迭代器遍历

map

#include 
#include 

int main() {
  std::map myMap = {{"apple", 1}, {"banana", 2}, {"cherry", 3}};

  // 使用迭代器遍历 map
  for (std::map::iterator it = myMap.begin(); it != myMap.end(); ++it) {
    std::cout << it->first << ": " << it->second << " ";
  }
  std::cout << std::endl;

  return 0;
}

迭代器失效是什么?如何避免?

迭代器失效是指迭代器指向的元素不再有效或不存在。这通常发生在容器修改后,例如插入、删除元素等。避免迭代器失效是编写健壮的 STL 代码的关键。

常见导致迭代器失效的操作:

  • vector
    deque
    :
    插入或删除元素可能导致所有迭代器失效。特别是在
    vector
    中,如果插入操作导致重新分配内存,则所有迭代器都会失效。
  • list
    :
    插入元素不会导致迭代器失效,删除元素只会使指向被删除元素的迭代器失效。
  • map
    set
    :
    插入元素不会导致迭代器失效,删除元素只会使指向被删除元素的迭代器失效。

避免迭代器失效的策略:

  1. 尽量使用返回值: 某些容器操作(例如

    erase
    )会返回指向下一个有效元素的迭代器。使用这些返回值可以避免迭代器失效。

    燕雀Logo
    燕雀Logo

    为用户提供LOGO免费设计在线生成服务

    下载
    std::vector vec = {1, 2, 3, 4, 5};
    for (auto it = vec.begin(); it != vec.end(); ) {
      if (*it % 2 == 0) {
        it = vec.erase(it); // erase 返回指向下一个元素的迭代器
      } else {
        ++it;
      }
    }
  2. 避免在循环中修改容器大小: 如果需要在循环中修改容器大小,可以考虑使用

    list
    map/set
    ,因为它们在插入和删除元素时对迭代器的影响较小。或者,可以先收集需要删除的元素,然后在循环结束后一次性删除。

  3. 使用范围 for 循环 (C++11 及以上): 范围 for 循环在某些情况下可以避免迭代器失效的问题,但需要注意,如果在循环体内修改容器大小,仍然可能导致未定义行为。

  4. 小心使用

    insert
    erase
    :
    vector
    deque
    中,
    insert
    erase
    操作会移动元素,导致迭代器失效。需要特别小心处理。

理解迭代器失效的原因和避免方法,可以帮助我们编写更可靠和高效的 STL 代码。

如何自定义迭代器?

虽然 STL 提供了丰富的迭代器类型,但在某些情况下,我们可能需要自定义迭代器来满足特定的需求。自定义迭代器需要实现特定的接口和行为。

自定义迭代器的步骤:

  1. 定义迭代器类: 创建一个类,用于表示自定义迭代器。

  2. 定义迭代器类型别名: 在类中定义一些类型别名,例如

    iterator_category
    ,
    value_type
    ,
    difference_type
    ,
    pointer
    ,
    reference
    。这些类型别名用于指定迭代器的类型和相关信息。

  3. 实现迭代器操作符: 重载迭代器需要支持的操作符,例如

    *
    ,
    ++
    ,
    ==
    ,
    !=
    等。

  4. 实现

    begin()
    end()
    方法:
    在容器类中实现
    begin()
    end()
    方法,返回自定义迭代器的实例。

示例:自定义一个简单的数组迭代器

#include 

template 
class ArrayIterator {
 public:
  using iterator_category = std::random_access_iterator_tag;
  using value_type = T;
  using difference_type = std::ptrdiff_t;
  using pointer = T*;
  using reference = T&;

  ArrayIterator(T* ptr) : m_ptr(ptr) {}

  reference operator*() const { return *m_ptr; }
  pointer operator->() const { return m_ptr; }

  ArrayIterator& operator++() {
    ++m_ptr;
    return *this;
  }

  ArrayIterator operator++(int) {
    ArrayIterator temp = *this;
    ++m_ptr;
    return temp;
  }

  ArrayIterator& operator--() {
    --m_ptr;
    return *this;
  }

  ArrayIterator operator--(int) {
    ArrayIterator temp = *this;
    --m_ptr;
    return temp;
  }

  ArrayIterator operator+(difference_type n) const { return ArrayIterator(m_ptr + n); }
  ArrayIterator operator-(difference_type n) const { return ArrayIterator(m_ptr - n); }

  difference_type operator-(const ArrayIterator& other) const { return m_ptr - other.m_ptr; }

  bool operator==(const ArrayIterator& other) const { return m_ptr == other.m_ptr; }
  bool operator!=(const ArrayIterator& other) const { return m_ptr != other.m_ptr; }
  bool operator<(const ArrayIterator& other) const { return m_ptr < other.m_ptr; }
  bool operator>(const ArrayIterator& other) const { return m_ptr > other.m_ptr; }
  bool operator<=(const ArrayIterator& other) const { return m_ptr <= other.m_ptr; }
  bool operator>=(const ArrayIterator& other) const { return m_ptr >= other.m_ptr; }

 private:
  T* m_ptr;
};

template 
class MyArray {
 public:
  using iterator = ArrayIterator;

  MyArray() {}

  iterator begin() { return iterator(m_data); }
  iterator end() { return iterator(m_data + N); }

  T& operator[](size_t index) { return m_data[index]; }
  const T& operator[](size_t index) const { return m_data[index]; }

 private:
  T m_data[N];
};

int main() {
  MyArray arr;
  arr[0] = 1;
  arr[1] = 2;
  arr[2] = 3;
  arr[3] = 4;
  arr[4] = 5;

  for (auto it = arr.begin(); it != arr.end(); ++it) {
    std::cout << *it << " ";
  }
  std::cout << std::endl;

  return 0;
}

这个示例展示了如何自定义一个简单的数组迭代器,并将其用于遍历自定义的数组类。自定义迭代器可以让我们更灵活地控制数据的访问方式,并与其他 STL 算法进行集成。

如何使用迭代器进行算法操作?

STL 算法通常使用迭代器作为输入,对容器中的元素进行操作。理解如何使用迭代器进行算法操作是掌握 STL 的关键。

示例:使用

std::copy
算法复制容器中的元素

#include 
#include 
#include 

int main() {
  std::vector source = {1, 2, 3, 4, 5};
  std::vector destination(source.size());

  // 使用 std::copy 算法复制 source 到 destination
  std::copy(source.begin(), source.end(), destination.begin());

  // 打印 destination 中的元素
  for (int element : destination) {
    std::cout << element << " ";
  }
  std::cout << std::endl;

  return 0;
}

示例:使用

std::transform
算法转换容器中的元素

#include 
#include 
#include 
#include 

int main() {
  std::vector source = {1, 2, 3, 4, 5};
  std::vector destination(source.size());

  // 使用 std::transform 算法将 source 中的元素乘以 2 并存储到 destination
  std::transform(source.begin(), source.end(), destination.begin(), [](int x) { return x * 2; });

  // 打印 destination 中的元素
  for (int element : destination) {
    std::cout << element << " ";
  }
  std::cout << std::endl;

  return 0;
}

示例:使用

std::find
算法查找容器中的元素

#include 
#include 
#include 

int main() {
  std::vector vec = {1, 2, 3, 4, 5};

  // 使用 std::find 算法查找元素 3
  auto it = std::find(vec.begin(), vec.end(), 3);

  if (it != vec.end()) {
    std::cout << "Found element: " << *it << std::endl;
  } else {
    std::cout << "Element not found" << std::endl;
  }

  return 0;
}

这些示例展示了如何使用迭代器与 STL 算法结合,对容器中的元素进行各种操作。掌握这些技巧可以让我们更高效地使用 STL。

相关专题

更多
硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

1048

2023.10.19

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

86

2025.10.17

php8.4实现接口限流的教程
php8.4实现接口限流的教程

PHP8.4本身不内置限流功能,需借助Redis(令牌桶)或Swoole(漏桶)实现;文件锁因I/O瓶颈、无跨机共享、秒级精度等缺陷不适用高并发场景。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

455

2025.12.29

java接口相关教程
java接口相关教程

本专题整合了java接口相关内容,阅读专题下面的文章了解更多详细内容。

11

2026.01.19

golang map内存释放
golang map内存释放

本专题整合了golang map内存相关教程,阅读专题下面的文章了解更多相关内容。

75

2025.09.05

golang map相关教程
golang map相关教程

本专题整合了golang map相关教程,阅读专题下面的文章了解更多详细内容。

36

2025.11.16

golang map原理
golang map原理

本专题整合了golang map相关内容,阅读专题下面的文章了解更多详细内容。

60

2025.11.17

java判断map相关教程
java判断map相关教程

本专题整合了java判断map相关教程,阅读专题下面的文章了解更多详细内容。

40

2025.11.27

AO3中文版入口地址大全
AO3中文版入口地址大全

本专题整合了AO3中文版入口地址大全,阅读专题下面的的文章了解更多详细内容。

1

2026.01.21

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C# 教程
C# 教程

共94课时 | 7.2万人学习

C 教程
C 教程

共75课时 | 4.1万人学习

C++教程
C++教程

共115课时 | 13.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号