[C++面试] 你了解视图吗?
一、入门
1、什么是 C++ 视图(View)?请简要说明其概念和用途
它提供了对序列(如数组、容器等)的非拥有性、只读或可写的访问。(就像是个透明的放大镜,它能让你去看一组数据,但它自己不拥有这些数据。)
- 避免数据的复制,提高性能。
- 提供统一的接口来处理不同类型的序列。
- 实现延迟计算,只有在需要时才进行实际的数据处理。
#include <iostream>
#include <ranges>
#include <vector>int main() {std::vector<int> numbers = {1, 2, 3, 4, 5};// 创建一个视图,它是对numbers向量的一个抽象表示auto view = std::views::all(numbers); for (auto num : view) {std::cout << num << " ";}std::cout << std::endl;return 0;
}
在这个例子中,std::views::all 创建了一个视图,它包含了 numbers 向量中的所有元素。通过视图可以遍历这些元素,而不需要复制数据。
2、std::views::transform 是干啥的?
td::views::transform 是个很有用的工具,它能对一组数据里的每个元素做转换。你可以把它想象成一个小魔法师,能把每个元素变成你想要的样子
3、 传统容器的区别
- 不持有数据:视图仅引用底层数据,不进行复制或所有权管理。
- 惰性计算:操作(如
transform或filter)在遍历时才会执行。 - 常量时间复杂度操作:构造、复制和移动的时间复杂度为O(1)
auto square = [](int x) { std::cout << "Processing " << x << std::endl; return x * x;
};
auto view = data | std::views::transform(square);
// 此时未调用square,直到遍历view时才输出日志
“|” 是范围(ranges)库中的管道运算符,它能够把一个范围(如 std::vector)和视图适配器进行连接。
auto squared = data | std::views::transform([](int x) { return x * x; });
std::views::transform是一个视图适配器,其作用是对范围中的每个元素执行转换操作。它接收一个可调用对象(通常是 lambda 表达式)作为参数,这个可调用对象会对每个元素进行处理。[](int x) { return x * x; }是一个 lambda 表达式,它接收一个int类型的参数x,并返回x的平方。auto squared借助auto关键字自动推导squared的类型。squared实际上是一个视图对象,它代表了对data中每个元素进行平方操作后的结果。需要注意的是,这里并没有立即计算平方值,而是在遍历时才会进行计算,这就是延迟计算。
std::vector<int> data{1, 2, 3, 4, 5};
auto result = data | std::views::filter([](int x) { return x % 2 == 0; }) // 过滤偶数| std::views::transform([](int x) { return x * 2; }); // 每个数乘2
// 遍历时才执行:先过滤出2,4 → 再转换为4,8
- 执行顺序:从左到右依次处理(先过滤再转换)。
- 零拷贝优化:中间不生成临时容器,内存效率高
4、视图与for_each的区别
- 视图:延迟计算,不修改原数据,支持链式操作(如
filter + transform)。 std::for_each:立即执行,需显式处理每个元素,无法组合操作。
// 视图:延迟计算,链式操作
auto result = data | std::views::filter(is_even) | std::views::transform(square);// std::for_each:立即执行,需手动处理
std::for_each(data.begin(), data.end(), [](int x) { /* 处理逻辑 */ });
二、进阶
1、如何使用视图进行数据过滤和转换?
#include <iostream>
#include <ranges>
#include <vector>int main() {std::vector<int> numbers = {1, 2, 3, 4, 5};// 过滤出偶数auto even_view = numbers | std::views::filter([](int x) { return x % 2 == 0; });// 将过滤后的偶数乘以2auto transformed_view = even_view | std::views::transform([](int x) { return x * 2; });for (auto num : transformed_view) {std::cout << num << " ";}std::cout << std::endl;return 0;
}
- 首先使用
std::views::filter视图适配器过滤出numbers向量中的偶数 - 然后使用
std::views::transform视图适配器将过滤后的偶数乘以 2 - 最后遍历转换后的视图并输出结果
2、视图的惰性求值如何实现?在性能优化中有何利弊?
实现机制:视图通过封装迭代器和函数对象,在遍历时动态应用操作(如transform_view存储转换函数,filter_view存储谓词)
- 优点:避免中间数据拷贝,节省内存;支持提前终止遍历(如
break时跳过后续计算) - 缺点:多次遍历同一视图可能导致重复计算(如
transform函数被多次调用),可通过std::ranges::to<std::vector>缓存结果优化
3、视图可能的问题 与 风险
若底层容器被修改、发生插入/删除(如vector扩容导致迭代器失效),视图可能引用无效内存。(图通过封装迭代器和函数对象)
最佳实践:
- 修改容器后,重新生成视图。
- 避免在视图生命周期内修改容器容量(如使用
std::list或预留容量)
4、如何实现视图的原地修改?
std::vector<int> data = {1, 2, 3};
data | std::views::transform([](int& x) { x *= 2; }); // 原地修改
三、高阶
1、自定义视图适配器需要注意哪些方面?请给出一个自定义视图适配器的示例。
自定义视图适配器时需要注意以下几点:
- 继承
std::ranges::view_interface类,以确保视图符合视图的接口要求。 - 实现必要的迭代器和范围相关的类型别名,如
iterator、sentinel等。 - 实现视图的构造函数和访问方法。
#include <iostream>
#include <ranges>
#include <vector>// 自己做的视图工具
template <std::ranges::input_range R>
class custom_view : public std::ranges::view_interface<custom_view<R>> {
private:R base_;
public:custom_view(R r) : base_(std::move(r)) {}auto begin() { return std::ranges::begin(base_); }auto end() { return std::ranges::end(base_); }
};// 做视图工具的工厂函数
template <std::ranges::input_range R>
auto make_custom_view(R&& r) {return custom_view<std::views::all_t<R>>(std::forward<R>(r));
}int main() {std::vector<int> numbers = {1, 2, 3, 4, 5};auto view = make_custom_view(numbers);for (auto num : view) {std::cout << num << " ";}std::cout << std::endl;return 0;
}
定义了一个自己的视图工具 custom_view,它继承了 std::ranges::view_interface。写了 begin 和 end 方法,这样就能一个一个地去看数据了。还写了一个工厂函数 make_custom_view 来创建这个视图工具。最后用这个工具去看 numbers 里的数字,并且把它们都输出出来。
2、实现一个“步长视图”(每隔N个元素取一个)
template <std::ranges::view V>
class StrideView : public std::ranges::view_interface<StrideView<V>> {V base_;size_t stride_;
public:StrideView(V base, size_t stride) : base_(base), stride_(stride) {}auto begin() { return std::ranges::begin(base_); // 实际需自定义迭代器步进逻辑}auto end() { return std::ranges::end(base_); }
};// 使用示例:每隔2个元素取一个
auto view = data | StrideView(2);
- 继承
view_interface,定义迭代器步进逻辑。 - 实现
begin()和end(),控制迭代器步长。
3、 视图如何与协程结合处理无限数据流?
场景:生成无限序列(如传感器数据),按需消费。内存友好,避免缓存全部数据。
generator<int> infinite_stream() {for (int i : std::views::iota(0) | std::views::transform(process_data)) {co_yield i; // 每次协程恢复时生成一个处理后的数据}
}
4、如何设计一个线程安全的视图?
template <typename T>
class thread_safe_view : public std::ranges::view_interface<thread_safe_view<T>> {std::mutex mtx;T& data;
public:auto begin() {std::lock_guard<std::mutex> lock(mtx);return std::begin(data);}// 类似实现 end()
};
- 在底层容器外部加锁,确保视图遍历时容器不被修改。
补充:视图的典型应用场景
- 大数据处理:避免复制GB级数据,用视图切片处理。
- 实时日志过滤:用
filter视图动态筛选关键日志。 - 游戏引擎:用
transform视图批量计算粒子效果位置。
相关文章:
[C++面试] 你了解视图吗?
一、入门 1、什么是 C 视图(View)?请简要说明其概念和用途 它提供了对序列(如数组、容器等)的非拥有性、只读或可写的访问。(就像是个透明的放大镜,它能让你去看一组数据,但它自己…...
Vue3 项目通过 docxtemplater 插件动态渲染 .docx 文档(带图片)预览,并导出
Vue3 项目通过 docxtemplater 插件动态渲染 .docx 文档(带图片)预览,并导出 预览安装插件示例代码项目目录结构截图实际效果截图 动态渲染 .docx 文档(带图片),预览、导出安装插件docx 模板文件内容完整代码…...
ollama迁移已下载的单个模型到服务器
ollama迁移已下载的单个模型到服务器 场景 ollama是面向用户级的,部署和运行都很简单,是否高效就另说了。但最起码,他能充分利用用户的硬件设备,在GPU不足也能调用cpu和内存去加持。 ollama运行的模型基本是量化版本的…...
Photoshop 2025安装教程包含下载安装包,2025最新版图文安装教程
文章目录 前言一、Photoshop 2025下载二、Photoshop 2025安装教程1. 安装包解压2. 找到安装程序3. 以管理员身份运行4. 安装选项设置5. 选择安装路径6. 开始安装7. 安装完成8. 启动软件9. 软件主界面 前言 无论你是专业设计师,还是刚接触图像处理的新手,…...
【Python · PyTorch】时域卷积网络 TCN
1. 概念 1.1 定义 TCN 是时域卷积网络(Temporal Convolutional Network)的简称。TCN是于2018年 Shaojie Bai 等人提出的一个处理时序数据的卷积模型。 TCN结合了CNN卷积并行性计算和RNN长期依赖的优势,CNN可在多个通道同时处理卷积核运算&…...
Mysql update更新数据执行流程
update 的执行流程是以select查询为基础执行的!!你不明白select执行流程?没关系,这篇博客照样让你明白,update执行流程! 存储引擎是什么? 如果把数据库比作一个大仓库,那么存储引擎…...
WMS WCS系统架构
1.1立体仓库现场网络架构图 1.2立体仓库WMS系统与WCS系统架构 1.3系统技术选型 WEB端技术:node.js、vue 、element、jquery、html、js、css等 API端技术:spring boot 、msyql、redis、mybatis等 WCS技术:c#、winform、OPC、socket、S7等 …...
数据结构5(初):续写排序
目录 1、外排序 2、计数排序 1、外排序 上一节中提到的排序都可以用来进行内排序,但是只有归并排序的思想可以用来进行外部排序,因为文件数据是没办法像数组那样进行访问的。 例如: #include <stdio.h> #include <assert.h> …...
ROS多机通信(三)——Ubuntu Ad-Hoc 组网通信配置指南
基本概念 Ad-Hoc 网络是一种简单的点对点无线网络,设备(称为节点)可以直接相互通信或者通过中继间接通信,而无需依赖中央接入点。在这种网络中,所有设备是对等的,没有固定的路由器或基础设施支持。 特点 …...
23种设计模式-状态(State)设计模式
状态设计模式 🚩什么是状态设计模式?🚩状态设计模式的特点🚩状态设计模式的结构🚩状态设计模式的优缺点🚩状态设计模式的Java实现🚩代码总结🚩总结 🚩什么是状态设计模式…...
ARM架构薄记2——ARM学习架构抓手(以ARMv7为例子)
ARM架构薄记2——ARM学习架构抓手(以ARMv7为例子) 架构学习需要学习哪一些部分呢?笔者接触过的架构有Intel-X86, AMD64,RISC-V和Arm架构(V7最多),笔者简单的翻了一些课本和教材,…...
STM32C011 进入停止模式和待机模式
对于STM32C011J4M3微控制器,你可以使用HAL库来实现进入停止模式(Stop Mode)和待机模式(Standby Mode)。下面是进入停止模式和待机模式的示例代码: 进入停止模式代码示例: #include "stm3…...
kaggle上经典泰坦尼克项目数据分析探索
之前了解在kaggle上这个项目很火,最近想要加强一下python数据分析,所以在kaggle上找到这个项目进行学习探索,下面是将一些学习资料以及过程整理出来。 一、首先我们了解一下项目背景以及如何找到这个项目。 kaggle项目地址: https://www.k…...
影刀魔法指令3.0:开启自动化新篇章
在数字化飞速发展的今天,自动化工具已经成为提升工作效率、优化工作流程的重要手段。影刀RPA作为一款强大的自动化软件,其最近推出的魔法指令3.0版本,更是让人大开眼界,为自动化操作带来了全新的可能性。 影刀魔法指令3.0简介 影…...
15 python 数据容器-字典
在 Python 的编程世界里,字典是一种超实用的数据类型,它就像打工人的工作资料夹,能把各种不同类型的信息有条理地存起来,还能快速找到你需要的内容。对于刚开始学习编程的小伙伴来说,掌握字典的用法,能让你…...
Linux的一些常见指令
一、ls指令 语法: ls (选项) 功能: ls可以查看当前目录下的所有文件和目录。 常用选项: -a:列出目录下的所有文件,包括以点(.)开头的隐含文件 。-d:将目录像文件一样显示,不显示其下的文件。…...
Pre-flash和Main flash
在相机拍照过程中,Pre-flash(预闪光) 和 Main flash(主闪光) 是常见的两种闪光灯使用模式,通常用于提高低光环境下的拍摄质量,尤其在自动曝光(AE)和自动对焦(…...
jmm-java内存模型
java内存模型----底层原理 底层原理 从Java代码到最终执行的CPU指令的流程: 最开始,我们编写的Java代码,是*.java文件在编译(javac命令)后,从刚才的*.java文件会变出一个新的Java字节码文件(…...
合宙780E开发学习-LUATOS-SOC云编译自定义固件
登录https://luatos.com 点击登录,使用合宙erp账号登录即可 点击右上角构建,点击右上角菜单新构建,自定义构建名称,可新建多个 勾选想要的组件 点击右上角保存修改,只有点击准备就绪(注意:一定…...
解决Centos使用yum命令报错“Cannot find a valid baseurl for repo: base/7/x86_64”问题
一、问题描述 我们在使用Centos7.9使用【sudo yum install influxdb2】命令安装influxDB数据库的时候提示“Loading mirror speeds from cached hostfile Could not retrieve mirrorlist http://mirrorlist.centos.org/release=7&arch=x86_64&repo=os&infra=stock …...
好用的Markdown阅读编辑器Typora破解记录
Typora破解 一、下载Typora二、安装Typora三、破解Typora 😀 记录一下Typora破解记录,怕不常用忘记咯,感觉自己现在的脑子就像我的肠子一样,刚装进去就么得了。。。😔 Typroa算是用起来很舒服的Markdown阅读器了吧&am…...
c#在work线程中怎样更新UI控件
最近笔者调试修改项目,碰到了c#在work线程中怎样更新UI控件中的场景,简单总结了下,主要有两个方法: 方法1:通过System.Windows.Application.Current.Dispatcher.Invoke来更新UI控件 System.Windows.Application.Curre…...
RabbitMQ三种队列深度解析:区别、场景与未来趋势
嗯,用户让我分析RabbitMQ三种队列的区别、应用场景、技术原理和未来趋势,还要写一篇三千字的文章。首先,我需要回顾一下搜索结果,看看有哪些资料可用。 根据搜索结果,RabbitMQ的三种队列是经典队列(Classi…...
自然语言处理(13:RNN的实现)
系列文章目录 第一章 1:同义词词典和基于计数方法语料库预处理 第一章 2:基于计数方法的分布式表示和假设,共现矩阵,向量相似度 第一章 3:基于计数方法的改进以及总结 第二章 1:word2vec 第二章 2:word2vec和CBOW模型的初步实现 第二章 3:CBOW模型…...
WebSocket接入SSL证书
目录 碎碎念解决方法创建 HTTPS WebSocket 服务器创建系统服务启动服务 碎碎念 在访问网站时,使用 HTTPS 非常重要。HTTPS 协议不仅可以确保数据传输的安全性,还可以防止中间人攻击和数据篡改等安全问题。任何没有 SSL 证书的内容都可能会被拒绝访问。因…...
无人机宽带自组网机载电台技术详解,50KM超远图数传输系统实现详解
以下是关于无人机宽带自组网机载电台技术以及50KM超远图数传输系统实现的详解: 无人机宽带自组网机载电台技术详解 无人机宽带自组网机载电台是一种专门为无人机设计的通信设备,它支持宽带数据传输和自组网功能。这种电台的实现技术涉及多个方面&#x…...
MySQL 表 t1 建立联合索引 (a, b, c),在 where a < ? and b > ? and c < ? 中哪些索引生效
文章目录 联合索引 abc 均范围扫描时的索引生效情况无回表 表数据量非常少无回表 表数据量多有回表总结 联合索引 abc 均范围扫描时的索引生效情况 场景:表 t1 建立联合索引 (a, b, c),在 where a < ? and b > ? and c < ? 中哪些索引生效…...
Spring Boot定时任务设置与实现
Spring Boot定时任务设置与实现 在Spring Boot中,可以使用Scheduled注解来创建定时任务。以下是一个简单的示例,展示了如何在项目启动后每5秒调用一次指定的方法。 1. 添加依赖 首先,确保你的pom.xml文件中包含Spring Boot的依赖ÿ…...
#vue中解决异步请求的竞态
// composables/useFetchWithoutRace.js import { ref } from vue; import axios from axios;// 定义一个可复用的 Composition 函数,处理带有竞态控制的异步请求 export function useFetchWithoutRace() {// 定义响应式变量 latestRequestId,用于追踪最…...
BP神经网络+NSGAII算法(保真)
BP神经网络NSGAII算法 非常适合用来当作实验验证自己的结论,构建一个神经网络模型,并使用NSGAII多目标优化算法来实现多领域的毕业论文的设计。仅仅使用简单的matlab代码就可以实现自己的多目标优化任务。 BP神经网络算法 我的任务是预测三个变量的值…...
