• 基于 range 的 for 循环和 auto


    基于 range 的 for 循环和 auto

    C++11 引入一种循环的新形式,叫基于 range 的 for 循环,它允许我们用更简单易读的形式遍历容器中的所有元素

    vector<int> v{1, 2, 3};
    for (int i : v) {
        cout << i << endl;
    }
    

    可以使用 auto 来让编译器来推导元素的类型,上面的循环可以改写为

    for (auto i : v) {
        cout << i << endl;
    }
    

    根据 auto 的推导规则,推导出的类型是初始值退化后的类型,即

    • 去掉引用
    • 去掉 const、volatile 限定符
    • 函数和数组将变为指针

    根据这个规则,上面循环推导出的类型应该是 int,这对于 int 这种标量类型可能没有问题,但如果容器里存的是类类型,就可能带来巨大的拷贝开销,因为每次做循环都需要创建容器元素的局部副本,这种情况下,应该用 auto &

    for (auto& elem : container)    // capture by (non-const) reference
    

    这种形式中修改 elem 将影响容器的内容

    对于模板代码,总是应该用这种形式,因为你没法确定模板类型的拷贝开销是否廉价

    如果是只读的,还应该给 auto 加上 const 限定符

    for (const auto& elem : container)    // capture by const reference
    

    代理迭代器

    如果容器使用“代理迭代器”(比如 std::vector ),应该使用

    for (auto&& elem : container)    // capture by &&
    

    假设我们想要用 range-for 遍历一个 std::vector 并修改它的元素

    vector<bool> v = {true, false, false, true};
    for (auto& x : v)
        x = !x;
    

    会发现上面这段代码无法通过编译,因为 std::vector 模板对 bool 类型做了模板特化,对 bool 元素做了打包处理以压缩空间(把 8 个布尔值存到一个字节里)

    由于你无法返回一个 bit 的引用,std::vector 用了一种叫“代理迭代器”的模式

    代理迭代器是一种迭代器,当它被解引用时,它不产生原始的 bool &,而是返回一个临时对象,它是可以转换为 bool 的代理类

    为了对 std::vector 使用 range-for 语法,必须使用 auto&& 来引用 bool 元素(关于 auto && 的推导规则请看这篇

    这种语法对于没有使用代理迭代器的容器也适用,因此在泛型代码里,最好的选择就是用这种形式来遍历修改容器元素


    __EOF__

  • 本文作者: 路过的摸鱼侠
  • 本文链接: https://www.cnblogs.com/ljx-null/p/16251778.html
  • 关于博主: 评论和私信会在第一时间回复。或者直接私信我。
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。
  • 相关阅读:
    Python 潮流周刊#54:ChatTTS 强大的文本生成语音模型
    什么是Java运算?Java运算好学吗?
    数据库 高阶语句2
    springboot+commons-pool2 连接池访问sftp
    (2) Java 8 实战第二版——补充 收集数据、并行数据处理能力与性能
    数据结构与算法之美-读书笔记3
    【Redis】第5讲 Redis的下载并安装
    2022最火的Linux性能分析工具--perf
    给灭霸点颜色看看
    Java并发 | 19.[锁机制] 偏向锁(CAS)
  • 原文地址:https://www.cnblogs.com/ljx-null/p/16251778.html