首页 > 后端开发 > C++ > 正文

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

P粉602998670
发布: 2025-09-19 09:45:01
原创
513人浏览过
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 <iostream>
#include <vector>

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

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

  // 使用 const_iterator 遍历 vector (只读)
  for (std::vector<int>::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 <iostream>
#include <list>

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

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

  return 0;
}
登录后复制

示例 3: 使用迭代器遍历

map
登录后复制

#include <iostream>
#include <map>

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

  // 使用迭代器遍历 map
  for (std::map<std::string, int>::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
    登录后复制
    )会返回指向下一个有效元素的迭代器。使用这些返回值可以避免迭代器失效。

    Alkaid.art
    Alkaid.art

    专门为Phtoshop打造的AIGC绘画插件

    Alkaid.art 153
    查看详情 Alkaid.art
    std::vector<int> 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 <iostream>

template <typename T>
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 <typename T, size_t N>
class MyArray {
 public:
  using iterator = ArrayIterator<T>;

  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<int, 5> 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 <iostream>
#include <vector>
#include <algorithm>

int main() {
  std::vector<int> source = {1, 2, 3, 4, 5};
  std::vector<int> 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 <iostream>
#include <vector>
#include <algorithm>
#include <functional>

int main() {
  std::vector<int> source = {1, 2, 3, 4, 5};
  std::vector<int> 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 <iostream>
#include <vector>
#include <algorithm>

int main() {
  std::vector<int> 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。

以上就是C++STL迭代器类型与用法详解的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

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