IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 《Effective Modern C++》学习笔记 - Item 13: 使用迭代器时尽可能使用 const_iterator -> 正文阅读

[C++知识库]《Effective Modern C++》学习笔记 - Item 13: 使用迭代器时尽可能使用 const_iterator

  • 本节的核心理念是 “尽可能使用 const 标识符” 这一大原则用在迭代器 iterator 上,idea本身没有什么值得争论的。接下来主要聊一聊C++98时很多情况为什么不用 const iterator,C++11/14做了什么改进,以及现在如何使用。

  • C++98中,假设有一个需求:在 std::vector<int> 中查找一个值 targetVal,然后在其位置(之后)插入另一个值 inserVal,如果找不到则插入在最后。很自然的可以写出如下代码:

std::vector<int> values;
int targetVal, insertVal;
...

// 作者贴心地没有用Item 9所述C++11的alias declaration(笑)
typedef std::vector<int>::iterator          IterT;
typedef std::vector<int>::const_iterator    ConstIterT;

IterT it = std::find(values.begin(), values.end(), targetVal);
values.insert(it, insertVal);
  • 以上代码中完全没有修改迭代器指向的内容。OK,你决定要把它们全改造为 const_iterator 版本:
ConstIterT cit = 
    std::find(static_cast<ConstIterT>(values.begin()),
              static_cast<ConstIterT>(values.end())
                , targetVal);

values.insert(static_cast<IterT>(cit), insertVal);	// error!
  • 且不论将 begin()end() 返回的非常量类型 IterT 转为常量 cit,又因为C++98的 insert() 只接受 non-const iterator,而不得不再次将 cit 转为IterT 这别扭的逻辑和繁杂的语法,你发现这样的代码竟然无法通过编译!原来,根本就没有一种方法能将 const_iterator 转为 iterator(C++11亦如此)!(笔者注:如果你也像我一样联想到了 const_cast,我要提醒你 const_cast 只能用在指针或引用上,而 const_iteratoriterator 是两个类!)
  • 终于,你决定放弃自己的理想,老老实实地用 non-const iterator——直到C++11闪亮登场!现在,const_iterator 的获取和使用都变得容易了:容器类提供函数 cbegincendconst_iterator 双手献上,使用迭代器来明确位置而不修改内容的STL函数(如 inserterase)现在使用 const_iterator 参数类型。C++11版本的代码如下:
auto cit = std::find(values.cbegin(), values.cend(), targetVal);
values.insert(cit, insertVal);
  • 笔者注:这里需要提醒一下:iteratorconst_iterator 的转换是轻易(等号赋值或cast)且可以隐式进行的。例如在MSVC的实现中, vectoriterator 类实际是由 const_iterator 类继承而来。cbegincend 函数的实现所幸就是直接return begin();return end();。(然而该例不属于标准而属于实现,GCC的实现看起来就完全不同)

  • 有时可能还会用更泛化的设计,将 cbegincend 等函数作为非成员函数(类似 std::find)。例如我们可以将以上逻辑写成一个通用的模板。使用它的优点之一是对原生的数组类型也支持,此时Container是一个数组的 const 引用,iteratorconst_iterator 对应的类型实际是指针和指向常量的指针。

// work in C++14
template<typename C, typename V>
void findAndInsert(C& container, const V& targetVal, const V& insertVal)
{
    using std::cbegin;
    using std::cend;

    auto it = std::find(cbegin(container), cend(container), targetVal);
    container.insert(it, insertVal);
}
  • 一个注意点:C++11标准制定时忽视了 std::cbeginstd::cend 这一系列非成员函数的加入,C++14修正了这一点。如果是在C++11中,需要自己进行实现,方法也很简单:像MSVC的 vector 中做的一样,直接返回 std::begin() std::cend() 即可。

总结

  1. 使用迭代器时尽可能使用 const_iterator
  2. 在最大化泛用性的设计中,倾向使用非成员函数版本的 begin, end, rbegin 等。
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-12-23 15:34:46  更:2021-12-23 15:35:02 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 13:09:21-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码