range for
1. 基于范围的for循环语法
C++11标准引入了基于范围的for循环特性,该特性隐藏了迭代器
的初始化和更新过程,让程序员只需要关心遍历对象本身,其语法也
比传统for循环简洁很多:
for ( range_declaration : range_expression )
{loop_statement;
}
基于范围的for循环不需要初始化语句、条件表达式以及更新表
达式,取而代之的是一个范围声明和一个范围表达式。其中范围声明
是一个变量的声明,其类型是范围表达式中元素的类型或者元素类型
的引用。而范围表达式可以是数组或对象,对象必须满足以下2个条件
中的任意一个。
1.对象类型定义了begin和end成员函数。
2. 定义了以对象参数为类型的begin和end普通函数。
#include <iostream>
#include <string>
#include <map>
std::map<int, std::string> index_map{ {1, "hello"}, {2, "world"},
{3, "!"} };
int int_array[] = { 0, 1, 2, 3, 4, 5 };
int main()
{for (const auto &e : index_map){std::cout << "key=" << e.first << ", value=" << e.second <<std::endl;}for (auto e : int_array){std::cout << e << std::endl;}
}
如果不会在循环过程中修改引用对象,那么推荐在范围声明中加上const限定符以帮助编译器生成更加高效的代码:
#include <iostream>
#include <vector>struct X
{X() { std::cout << "default ctor" << std::endl; }X(const X& other){std::cout << "copy ctor" << std::endl;}
};int main()
{std::vector<X> x(10);std::cout << "for (auto n : x)" << std::endl;for (auto n : x){}std::cout << "for (const auto &n : x)" << std::endl;for (const auto &n : x){}
}
2. 实现自己的range-for
//since C++17, until C++20for (range-declaration : range-expression )
{loop-statement
}The above syntax produces code equivalent to the following except for the lifetime expansion of temporaries of range-expression.
{auto && __range = range-expression ; //gcc//auto &_range = range-expression; //clangauto __begin = begin-expr ;auto __end = end-expr ;for ( ; __begin != __end; ++__begin){range-declaration = *__begin;loop-statement}
}
其中operator *用于编译器生成解引用代码,operator !=用于生成循环条件代码,而前缀版本的operator ++用于更新迭代器。
#include <iostream>template<typename T, size_t L>
class Iter
{
public:Iter(T* data, size_t idx):data{data}, idx{idx}{}T& operator*(){return *(data + idx);}Iter& operator++()//前缀operator ++{idx++;return *this;}bool operator != (const Iter& other){return other.idx != this->idx;}private:size_t idx{0};T* data;
};template<typename T, size_t L>
class array
{
public:using iterator = Iter<T, L>;array(std::initializer_list<T> list){T * ptr = data;for (const auto e : list){*ptr = e;ptr++;}}iterator begin(){return iterator(data, 0);}iterator end(){return iterator(data, L);}
private:T data[L]{};
};int main(void)
{array<int, 4> arr{10,20,30,40};for(auto iter = arr.begin(); iter != arr.end(); ++iter){std::cout << *iter << ' ';}for (const auto i : arr){std::cout << i << ' ';}std::cout << std::endl;
}
以上代码,类模板array中实现了iterator begin()和 iterator end(),在迭代器类Iter中实现了operator*(), operator++()[注意这里是前缀operator++],以及operator!=。
3. 临时范围表达式的陷阱
无论是C++11还是C++17,基于范围的for循环伪代码
//since C++17, until C++20
for (range-declaration : range-expression )
{
loop-statement
}
The above syntax produces code equivalent to the following except for the lifetime expansion of temporaries of range-expression.
{
auto && __range = range-expression ; //gcc版本
//auto &_range = range-expression; //clang版本
auto __begin = begin-expr ;
auto __end = end-expr ;
for ( ; __begin != __end; ++__begin)
{
range-declaration = *__begin;
loop-statement
}
}
对于下面这个例子代码
#include <iostream>
#include <vector>class RangeFor
{
public:std::vector<int>& items() { return data; }
private:std::vector<int> data{10, 20, 30, 40};
};RangeFor foo()
{RangeFor data;return data;
}int main(void)
{/*step 1: foo() return rvalue;step 2: items() return l_val_ref of rvalue.step 3: __range is an align for l_val_ref.step 4: rvalue(temp value) destory.now __range reference to dangling refenence.*/for (const auto& x : foo().items()) //gcc: unexcepted number//clang: segmentation fault{std::cout << x << " ";}return 0;
}
我们从C++ Insights分析看:
#include <iostream>
#include <vector>class RangeFor
{public: inline std::vector<int, std::allocator<int> > & items(){return this->data;}private: std::vector<int, std::allocator<int> > data;public: // inline RangeFor(RangeFor &&) noexcept = default;// inline ~RangeFor() noexcept = default;// inline constexpr RangeFor() noexcept(false) = default;
};RangeFor foo()
{RangeFor data = RangeFor() /* NRVO variable */;return data;
}int main()
{{std::vector<int, std::allocator<int> > & __range1 = foo().items();__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > > __begin1 = __range1.begin();__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > > __end1 = __range1.end();for(; __gnu_cxx::operator!=(__begin1, __end1); __begin1.operator++()) {int const & x = __begin1.operator*();std::operator<<(std::cout.operator<<(x), " ");}}return 0;
}
从clang角度编译器看: std::vector<int, std::allocator<int> > & __range1 = foo().items();
foo()返回临时右值,这个临时右值调用items返回了一个左值引用,然后 __range有引用了这个临时右值接口items返回的左值引用;这个句子结束后,这个临时右值销毁了,这个时候__range其实引用的是一个已经不存在对象的数据。
auto && __range = range-expression ;
这个是是cpp reference上说的(应该是gcc版本的)。其最终结果也是一样的;我们来分析下上面那段代码:
/*
step 1: foo() return temp rvalue;
step 2: items() return l_val_ref of rvalue.
step 3: __range is an alias for l_val_ref.
step 4: rvalue(temp value) destory.
now __range reference to dangling refenence.
*/
for (const auto& x : foo().items()) //gcc: unexcepted number
//clang: segmentation fault
{
std::cout << x << " ";
}
可能这里有些人觉得 定义了const auto&x可以捕获临时变量,这个是没错的;对于这个range-for来回代码相当于如下:
#include <iostream>
#include <vector>#include <string>class RangeFor
{
public:RangeFor() : data("rangeFor") { std::cout << "ctor" << std::endl; }std::string& getItems(){std::cout << "get data" << std::endl;return data;}~RangeFor(){std::cout << "dtor" << std::endl;data = "";}private:std::string data;
};RangeFor foo()
{RangeFor data;return data;
}int main(void)
{/*step 1: foo() return rvalue;step 2: items() return l_val_ref of rvalue.step 3: vec is an align for l_val_ref.step 4: rvalue(temp value) destory.*/const auto& ret = foo().getItems();//note: now vec reference to dangling refenence.if (ret.empty()){std::cout << "empty string" << std::endl;}else{std::cout << ret << std::endl;}return 0;
}
const auto& ret = foo(), getItems();这个 const左值引用ret作用于getItems返回的左值引用,这个getItems返回的左值引用(打比喻是毛)的真真数据是foo()返回的临时变量(打比喻是皮),这行代码结束后,临时变量被销毁了。getItems返回的左值引用,用一句话总结就是:皮之不存毛将焉附!
4. 基于范围的for 循环的初始化
C++17 引入了if 和switch 控制结构的可选初始化,C++20 现在为基于范围的for 循环引入了这
样一个可选的初始化。
for ( init-statement(optional); range-declaration : range-expression )
{
loop-statement
}
The above syntax produces code equivalent to the following:
{
init-statement
auto && __range = range-expression ;
auto __begin = begin-expr ;
auto __end = end-expr ;
for ( ; __begin != __end; ++__begin)
{
range-declaration = *__begin;
loop-statement
}
}
我们来看个代码示例:
#include <iostream>
#include <vector>class RangeFor
{
public:std::vector<int>& items() { return data; }
private:std::vector<int> data{10, 20, 30, 40};
};RangeFor foo()
{RangeFor data;return data;
}int main(void)
{//const auto& thing = foo();//for (const auto& x : thing.items())// C++17for (auto thing = foo(); const auto& x :thing.items()) //since c++20{std::cout << x << " ";}return 0;
}
相关文章:
range for
1. 基于范围的for循环语法 C11标准引入了基于范围的for循环特性,该特性隐藏了迭代器 的初始化和更新过程,让程序员只需要关心遍历对象本身,其语法也 比传统for循环简洁很多: for ( range_declaration : range_expression ) {loo…...
leetcode230 二叉搜索树中第K小的元素
题目 给定一个二叉搜索树的根节点 root ,和一个整数 k ,请你设计一个算法查找其中第 k 个最小元素(从 1 开始计数)。 示例 输入:root [5,3,6,2,4,null,null,1], k 3 输出:3 解析 这道题应该是能做出…...
.Net Core学习笔记 框架特性(注入、配置)
注:直接学习的.Net Core 6,此版本有没有startup.cs相关的内容 项目Program.cs文件中 是定义项目加载 启动的地方 //通过builder对项目进行配置、服务的加载 var builder WebApplication.CreateBuilder(args); builder.Services.AddControllers();//将…...
利用AI技术做电商网赚,这些百万级赛道流量,你还不知道?!
大家好,我是向阳 AI技术的飞速扩展已经势不可挡,不管你承不承认,AI 已经毫无争议的在互联网中占有一席之地了 无论你是做内容产业的,还是做电商的,你现在都躲不开 AI。 现在互联网行业的竞争就是这么残酷 互联网行业…...
leetcode-560 和为k的数组
一、题目描述 给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的子数组的个数 。 子数组是数组中元素的连续非空序列。 注意:nums中的元素可为负数 输入:nums [1,1,1], k 2 输出:2输入:num…...
Spring Boot实战指南:从入门到企业级应用构建
目录 一、引言 二、快速入门 1. 使用Spring Initializr创建项目 三、Spring Boot基础概念与自动配置 1. 理解SpringBootApplication注解 2. 自动配置原理 3. 查看自动配置报告 四、Spring Boot核心特性及实战 1. 外部化配置 2. Actuator端点 3. 集成第三方库 五、Sp…...
OneAPI接入本地大模型+FastGPT调用本地大模型
将Ollama下载的本地大模型配置到OneAPI中,并通过FastGPT调用本地大模型完成对话。 OneAPI配置 新建令牌 新建渠道 FastGPT配置 配置docker-compose 配置令牌和OneAPI部署地址 配置config.json 配置调用的渠道名称和大模型名称 {"systemEnv": {&qu…...
Training-Free Consistent Text-to-Image Generation # 论文阅读
URL https://arxiv.org/pdf/2402.03286 TL;DR 2024 年 2 月 nvidia 的文章。提出了一种不需要任何额外训练的主体保持方法,可以一次生成的 batch 中,通过多个 prompt 生成对应的多张图片,这些图片都可以拥有一个主体。 本文提出的方法通过…...
Spring 中常用的手动装载 bean 方法
在 Spring 的 bean 装载条件中,虽然 Spring 给我们提供了非常好用便捷的 Condition 相关注解,但是很多时候 Condition 相关注解并不满足我们的需求,我需要更复杂的条件手动控制是否装置 bean。这个时候我们就可以实现 Spring 为我们提供的几个…...
如何合理设置Java线程池大小
如何合理设置Java线程池大小:依据任务类型定制策略 Java线程池的合理配置直接关系到系统性能和资源利用率。根据任务性质的不同,合理的线程池大小设置策略也有所区别,主要包括CPU密集型、IO密集型及混合型任务。 1. CPU密集型任务 特点&am…...
python3 pandas
pandas - Python Data Analysis Library...
【B站 heima】小兔鲜Vue3 项目学习笔记Day02
文章目录 Pinia1.使用2. pinia-计数器案例3. getters实现4. 异步action5. storeToRefsx 数据解构保持响应式6. pinia 调试 项目起步1.项目初始化和git管理2. 使用ElementPlus3. ElementPlus 主题色定制4. axios 基础配置5. 路由设计6. 静态资源初始化和 Error lens安装7.scss自…...
RedisTemplate 实现基于 Value 操作的简易锁机制
在高并发场景下,确保操作的原子性和避免竞态条件至关重要。Redis 提供了丰富的数据结构和操作,是实现分布式锁的一个高效选择。本文将介绍如何使用 RedisTemplate 的 opsForValue().setIfAbsent() 方法来实现一种简单的锁机制,并提供一个示例…...
其它高阶数据结构⑦_Skiplist跳表_概念+实现+对比
目录 1. Skiplist跳表的概念 2. Skiplist跳表的效率 3. Skiplist跳表的实现 3.1 力扣1206. 设计跳表 3.2 Skiplist的初始化和查找 3.3 Skiplist的增加和删除 3.4 Skiplist的源码和OJ测试 4. 跳表和平衡搜索树/哈希表的对比 本篇完。 1. Skiplist跳表的概念 skiplist是…...
力扣230. 二叉搜索树中第K小的元素
Problem: 230. 二叉搜索树中第K小的元素 文章目录 题目描述思路复杂度Code 题目描述 思路 直接利用二叉搜索树中序遍历为一个有序序列的特性: 记录一个int变量rank,在中序遍历时若当前rank k则返回当前节点值 复杂度 时间复杂度: O ( n ) O(n) O(n);其…...
Linux_应用篇(07) 系统信息与系统资源
在应用程序当中,有时往往需要去获取到一些系统相关的信息,譬如时间、日期、以及其它一些系统相关信息,本章将向大家介绍如何通过 Linux 系统调用或 C 库函数获取系统信息, 譬如获取系统时间、日期以及设置系统时间、日期等&#x…...
基于Vue的验证码实现
一、验证码核心实现 创建slide-verify.vue,代码如下: <template><divclass"slide-verify":style"{ width: w px }"id"slideVerify"onselectstart"return false;"><!-- 图片加载遮蔽罩 -->&…...
P4【力扣217,389,496】【数据结构】【哈希表】C++版
【217】存在重复元素 给你一个整数数组 nums 。如果任一值在数组中出现 至少两次 ,返回 true ;如果数组中每个元素互不相同,返回 false 。 示例 1: 输入:nums [1,2,3,1] 输出:true 示例 2:…...
PE文件(六)新增节-添加代码作业
一.手动新增节添加代码 1.当预备条件都满足,节表结尾没有相关数据时: 现在我们将ipmsg.exe用winhex打开,在节的最后新增一个节用于存放我们要增加的数据 注意:飞鸽的文件对齐和内存对齐是一致的 先判断节表末尾到第一个节之间…...
ICRA 2024: NVIDIA 联合多伦多大学、加州大学伯克利分校、苏黎世联邦理工学院等研究人员开发了精细操作的手术机器人
英伟达(NVIDIA)正与学术研究人员合作,研究手术机器人。 NVIDIA 联合多伦多大学、加州大学伯克利分校、苏黎世联邦理工学院和佐治亚理工学院的研究人员开发了 ORBIT-Surgical,一个训练机器人的模拟框架,可以提高手术团…...
8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...
最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...
微信小程序 - 手机震动
一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注:文档 https://developers.weixin.qq…...
微信小程序云开发平台MySQL的连接方式
注:微信小程序云开发平台指的是腾讯云开发 先给结论:微信小程序云开发平台的MySQL,无法通过获取数据库连接信息的方式进行连接,连接只能通过云开发的SDK连接,具体要参考官方文档: 为什么? 因为…...
python执行测试用例,allure报乱码且未成功生成报告
allure执行测试用例时显示乱码:‘allure’ �����ڲ����ⲿ���Ҳ���ǿ�&am…...
C# 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
SQL慢可能是触发了ring buffer
简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...
学习一下用鸿蒙DevEco Studio HarmonyOS5实现百度地图
在鸿蒙(HarmonyOS5)中集成百度地图,可以通过以下步骤和技术方案实现。结合鸿蒙的分布式能力和百度地图的API,可以构建跨设备的定位、导航和地图展示功能。 1. 鸿蒙环境准备 开发工具:下载安装 De…...
vue3 daterange正则踩坑
<el-form-item label"空置时间" prop"vacantTime"> <el-date-picker v-model"form.vacantTime" type"daterange" start-placeholder"开始日期" end-placeholder"结束日期" clearable :editable"fal…...
【Kafka】Kafka从入门到实战:构建高吞吐量分布式消息系统
Kafka从入门到实战:构建高吞吐量分布式消息系统 一、Kafka概述 Apache Kafka是一个分布式流处理平台,最初由LinkedIn开发,后成为Apache顶级项目。它被设计用于高吞吐量、低延迟的消息处理,能够处理来自多个生产者的海量数据,并将这些数据实时传递给消费者。 Kafka核心特…...
