[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、 传统容器的区别

  • 不持有数据:视图仅引用底层数据,不进行复制或所有权管理。
  • 惰性计算:操作(如transformfilter)在遍历时才会执行。
  • 常量时间复杂度操作:构造、复制和移动的时间复杂度为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 类,以确保视图符合视图的接口要求。
  • 实现必要的迭代器和范围相关的类型别名,如 iteratorsentinel 等。
  • 实现视图的构造函数和访问方法。
#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()
};
  • 在底层容器外部加锁,确保视图遍历时容器不被修改。

 

补充:视图的典型应用场景

  1. 大数据处理:避免复制GB级数据,用视图切片处理。
  2. 实时日志过滤:用filter视图动态筛选关键日志。
  3. 游戏引擎:用transform视图批量计算粒子效果位置。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/41623.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【测试开发】OKR 小程序端黑盒测试报告

【测试报告】OKR 小程序端 项目名称版本号测试负责人测试完成日期联系方式OKR 小程序端4.0马铭胜2025-03-2515362558972 1、项目背景 1.1 OKR 用户端 在如今这个快节奏的时代中&#xff0c;个人和组织的成长往往依赖于清晰、明确且意义深远的目标。然而&#xff0c;如何设定…

【C++】内存模型分析

在 C 语言中&#xff0c;程序运行时的内存通常被划分为以下几个区域&#xff1a; 代码区&#xff08;Text Segment&#xff09;常量区&#xff08;Constant Segment&#xff09;全局/静态区&#xff08;Data Segment&#xff0c;包含静态数据段和 BSS 段&#xff09;堆区&…

关于解决Ubuntu终端及系统字体大小的问题

在Ubuntu中调整终端和系统字体大小可以通过以下方法&#xff08;可能不仅仅只是这几种&#xff09;实现&#xff1a; 1. 调整系统字体大小 打开终端并输入以下命令&#xff0c;安装GNOME Tweaks&#xff0c;等待安装完成&#xff1a; sudo apt install gnome-tweaks 接着进行…

java8循环解压zip文件---实现Excel文件数据追加

java8循环追加Excel数据 实际遇到问题&#xff1a;定期获取zip文件&#xff0c;zip文件内有几个固定模板的Excel文件&#xff0c;有的Excel文件可能还包含多个sheet。 有段时间一次性获取到好几个zip包&#xff0c;需要将这些包都解压&#xff0c;并且按照不同的文件名、sheet进…

内网渗透技术 Docker逃逸技术(提权)研究 CSMSF

目录 如何通过上传的webshell判断当前环境是否是物理环境还是Docker环境 方法一&#xff1a;检查文件系统 方法二&#xff1a;查看进程 方法三&#xff1a;检查网络配置 方法四&#xff1a;检查环境变量 方法五&#xff1a;检查挂载点 总结 2. 如果是Docker环境&#x…

MTK平台 Android12-Android13 默认搜狗输入法

系统默认搜狗输入法功能实现 文章目录 需求&#xff1a;场景 参考资料需求实现内置搜狗输入法配置第三方apk .mk 和 搜狗安装包&#xff0c;不可卸载方式搜狗输入法module 配置到系统device.mk 中去 设置搜狗输入法为默认输入法给输入法授权&#xff0c;默认所有权限 总结思考 …

一周掌握Flutter开发--8. 调试与性能优化(上)

文章目录 8. 调试与性能优化核心技能8.1 使用 Flutter DevTools 分析性能8.2 检查 Widget 重绘&#xff08;debugPaintSizeEnabled&#xff09;8.3 解决 ListView 卡顿&#xff08;ListView.builder itemExtent&#xff09; 其他性能优化技巧8.4 减少 build 方法的调用8.5 使用…

【区块链安全 | 第一篇】密码学原理

文章目录 1.哈希函数1.1 哈希函数的性质1.2 常见哈希算法1.3 Merkle Tree&#xff08;默克尔树&#xff09;1.4 HMAC&#xff08;哈希消息认证码&#xff09; 2. 公钥密码学2.1 对称加密 vs 非对称加密2.2 RSA 算法2.3 ECC&#xff08;椭圆曲线密码学&#xff09;2.4 Diffie-He…

vim的一般操作(分屏操作) 和 Makefile 和 gdb

目录 一. vim的基本概念 二. vim基础操作 2.1 插入模式 aio 2.2 [插入模式]切换至[正常模式] Esc 2.3[正常模式]切换至[末行模式] shift ; 2.4 替换模式 Shift R 2.5 视图&#xff08;可视&#xff09;模式 (可以快速 删除//注释 或者 增加//注释) ctrl v 三&…

NFC 智能门锁全栈解决方案:移动端、服务器、Web 管理平台

目录 一、系统整体架构 二、移动端 APP 开发 2.1 开发环境与基础准备 2.2 主要功能模块 2.3 示例代码&#xff08;Android/Kotlin 简化示例&#xff09; 三、后台服务开发 3.1 环境准备 3.2 主要功能 3.3 示例代码&#xff08;Node.js Express 简化示例&#xff09; …

系统与网络安全------网络应用基础(5)

资料整理于网络资料、书本资料、AI&#xff0c;仅供个人学习参考。 虚拟化 虚拟化技术原理概述虚拟化虚拟化实现条件常见的虚拟化软件产品 VMware应用实战安装VMware Workstation创建新虚拟机虚拟机的硬件配置调整 虚拟化高级应用虚拟机备份虚拟机快照 虚拟化技术 原理概述 虚…

Postman 下载文件指南:如何请求 Excel/PDF 文件?

在 Postman 中进行 Excel/PDF 文件的请求下载和导出&#xff0c;以下是简明的步骤&#xff0c;帮助你轻松完成任务。首先&#xff0c;我们将从新建接口开始&#xff0c;逐步引导你完成整个过程。 Postman 请求下载/导出 excel/pdf 文件教程

华为HCIE学习指南,如何更好的学习HCIE?

新盟教育 专注华为认证培训十余年 为你提供认证一线资讯&#xff01; 在竞争激烈的ICT行业&#xff0c;华为HCIE认证犹如一颗璀璨的明珠&#xff0c;散发着耀眼的光芒。它不仅是对个人技术能力的高度认可&#xff0c;更是开启高薪职业大门的钥匙。然而&#xff0c;华为HCIE学习…

贪心算法——c#

贪心算法通俗解释 贪心算法是一种"每一步都选择当前最优解"的算法策略。它不关心全局是否最优&#xff0c;而是通过局部最优的累积来逼近最终解。优点是简单高效&#xff0c;缺点是可能无法得到全局最优解。 一句话秒懂 自动售货机找零钱&#xff1a;用最少数量的…

架构思维:如何设计一个支持海量数据存储的高扩展性架构_数据分片、存储、复制与一致性的原理性问题

文章目录 PRE引言1. 数据分片策略Hash取模分片一致性Hash分片Range分片分片设计原理核心设计模块分片规则定义动态分片调整路由与负载均衡 应对热点的关键技术多级分片&#xff08;Hierarchical Sharding&#xff09;副本分散策略缓存层配合 典型应用场景优缺点分析 2. 应对热点…

Jenkins最新版,配置Gitee私人令牌和Gitee凭证

jenkins 配置Gitee私人令牌和凭证 jenkins 版本&#xff1a;Jenkins 2.492.2 Gitee配置 Jenkins配置gitee插件&#xff0c;需要先申请gitee私钥。 安装gitee插件 申请Gitee私人令牌&#xff0c;后面还需要添加凭证。 测试链接&#xff0c;并保存 配置凭证

ORACLE RAC ASM双存储架构下存储部分LUN异常的处理

早上接到用户电话&#xff0c;出现有表空间不足的告警&#xff0c;事实上此环境经常巡检并且有告警系统&#xff0c;一开始就带着有所疑惑的心理&#xff0c;结果同事在扩大表空间时&#xff0c;遇到报错 ORA-15401/ORA-17505,提示ASM空间满了&#xff1a; ALERT日志&#xff1…

Windows下docker使用教程

docker安装 镜像制作镜像加载容器创建更新镜像导出镜像 Windows10安装dockerdocker image制作docker 镜像加载docker 容器创建更新imageimage 导出为.tar文件 #以Windows10 、11为例 linux和Windows区别在于docker安装的程序是哪个操作系统的&#xff0c;后面的内容其实不变 …

9.4分漏洞!Next.js Middleware鉴权绕过漏洞安全风险通告

今日&#xff0c;亚信安全CERT监控到安全社区研究人员发布安全通告&#xff0c;Next.js 存在一个授权绕过漏洞&#xff0c;编号为 CVE-2025-29927。攻击者可能通过发送精心构造的 x-middleware-subrequest 请求头绕过中间件安全控制&#xff0c;从而在未授权的情况下访问受保护…

代码随想录算法训练营Day12 | Leetcode 226翻转二叉树、101对称二叉树、104二叉树的最大深度、111二叉树的最小深度

代码随想录算法训练营Day12 | Leetcode 226翻转二叉树、101对称二叉树、104二叉树的最大深度、111二叉树的最小深度 一、翻转二叉树 相关题目&#xff1a;Leetcode226 文档讲解&#xff1a;Leetcode226 视频讲解&#xff1a;Leetcode226 1. Leetcode226.翻转二叉树 给你一棵二…