资讯动态

【C++ 面试真题】22. 聊聊 C++ 的 pair、tuple 与 optional

发布时间:2026/8/20 1:24:39 来源:尧图企业网站定制
【C 面试真题】聊聊 C 的 pair、tuple 与 optional“函数想返回两个值怎么办”“查找失败怎么表达’没有’”——这些都是值语义打包问题把若干个值或没有值装进一个对象类型系统替你把关。背得出pair 存两个、tuple 存多个只是及格真考你的是解包三代写法、返回值怎么选、optional 和指针表达可空差在哪。本文把打包三兄弟一次讲透。一、开场值语义的打包三兄弟❓ pair、tuple、optional 各是什么✅ 都是把值装进一个对象的工具分工不同工具引入回答的问题pairC98固定装2 个值tuple[C11]装任意个值optionalT[C17]装一个值或没有回答思路先报两个、多个、一个或没有这条线再点一句共性——它们都是值语义装的是内容的拷贝自动析构、不涉及所有权。面试官会顺着问解包和选型。二、pair最简单的二元组❓ pair 怎么用✅ 两个公开成员first、secondpairstring,intp{tom,18};coutp.first;// tomcoutp.second;// 18autoqmake_pair(tom,18);// 类型自动推导pair 最常见的身影在容器里——map的每个元素就是pairconst Key, Value。 pair 自带字典序比较先比 first相等再比 second。正因如此sort一排 pair、map 按 key 排序才天然成立vectorpairint,string一句 sort 就是二级排序。三、tuple任意个值❓ tuple 怎么取值✅ 按下标或按类型取编译期确定tuplestring,int,doublet{tom,18,1.75};coutget0(t);// tomcoutgetstring(t);// 按类型不重复才行元信息编译期可查tuple_size是个数、tuple_element是类型。两个配套工具// applytuple 展开成函数实参apply(func,make_tuple(1,2.0));// tuple_cat多个 tuple 拼接autobigtuple_cat(make_tuple(1),make_tuple(2.5));⚠️tuple 没有成员名——只能 geti 按位取可读性靠纪律。这是它和具名 struct最大的差距也是后面选型的关键。四、解包三代演进tie → 结构化绑定❓ 接收这些返回值有哪些写法✅ 三代演进越写越顺第一代按位置取——res.first、get0(res)下标满天飞。第二代tie 解包[C11]——把已有变量按引用接出来string name;intscore;tie(name,score)make_pair(tom,18);// 不想接的用 ignore 跳过tie(ignore,score)make_pair(tom,18);第三代结构化绑定[C17]——声明即解包现在的主流auto[name,score]make_pair(tom,18);// pair、tuple、struct、数组都支持 结构化绑定还能绑引用auto [k, v] : m遍历 map 直接改值和常量引用const auto只读零拷贝——tie 做不到这么自然。tie 仅剩复用旧变量 ignore的场景。五、optional值或空❓ optional 解决什么问题✅ 解决用魔法值表示没有的痛点。过去查找失败返回 -1指针为空表示没有全靠约定optional 把可能没有变成类型的一部分optionalintfindAge(conststringname);autorfindAge(tom);if(r.has_value()){cout*r;// 有值才解引用}coutr.value_or(0);// 没有就兜底// 语法糖if (r) 有值、if (!r) 空⚠️对空 optional 解引用*是未定义行为——value()才会抛异常。判空后才能解或直接value_or。和指针表达可空的区别高频指针同时暗示指向别处的借用、要不要 delete语义混浊optional 是纯值语义——装的就是自己的拷贝不涉内存管理、不存在悬空int*findAge(...);// 借用拥有猜optionalintfindAge(...);// 有值/没有仅此而已它还是延迟初始化的占位——类成员构造时还定不下来之后emplace原地构造structConn{optionalSocketsock_;voidconnect(){sock_.emplace(fd);}};六、多返回值返回什么❓ 函数要返回多个值或可能失败的结果怎么选✅ 一张表定案需求首选语义明显的二元组key-valuepair三个以上、字段含义不直观具名 struct“成功才有结果”optionalT“成功/失败 原因 结果”struct 或 expected[C23]// ❌ 老写法魔法值 出参boolfindAge(conststring,intout);// ✅ 新写法类型即文档optionalintfindAge(conststringname);选型一句话二元组 pair、多元 struct、可空 optional——结构化绑定对三者通吃名字白拿不亏。七、实用细节❓ 还有哪些值得知道的细节✅ 四个高频细节① 结构化绑定配 if 初始化——插入 判重一行写完if(auto[it,ok]m.insert({k,v});ok){// 插入成功才进来}② 逐成员构造与比较——pair/tuple 的拷贝、移动、比较都是逐成员进行成员是 string 就有 string 的代价没有魔法。③ optional 的大小——就是 T 的存储加一个标志常打进 padding零堆分配sizeof(optionalint)通常 8 字节性能和传指针同量级。④ 聚合初始化直接花括号构造mapstring, int m{{a,1},{b,2}}里的每个{a,1}就是 pair。八、面试高频追问❓ Q1结构化绑定和 tie 的本质区别✅ tie 是给已有变量赋值的表达式要求变量先存在结构化绑定是声明新名字的语句类型自动推导支持引用与 const 修饰。日常新代码一律结构化绑定tie 只剩复用旧变量 ignore 跳过的场景。❓ Q2geti(t) 里的 i 能是运行期变量吗✅ 不能。i是编译期常量——tuple 的类型在编译期定死元素位置是类型信息的一部分。tuple 没有 for 循环遍历要靠 index_sequence 或 apply 折叠表达式做编译期展开。❓ Q3optionalint 和返回指针性能上有差吗✅ 没有实质差别——内联存储、传参走寄存器同量级。选 optional 不是为了性能是为了语义干净调用方一眼知道可能没有且不暗示借用或需要释放。❓ Q4optionalT装引用合法吗✅ 不合法标准明确不支持。要可空引用就optionalreference_wrapperT或者老实用指针表达借用。❓ Q5make_pair / make_tuple 存在的意义✅ 两个字推导。免写模板参数类型按实参推导兜底。[C17]有了类模板实参推导CTADpair p{tom, 18}直接写也行make 系列使命小了一半。❓ Q6optional 和 pairbool, T 都能表达成功结果哪个好✅ optional 好。pairbool,T 里 T 永远存在失败时还是得构造一个假值调用方还容易搞混 first/secondoptional 的空状态是内置语义value_or、判空一气呵成。[C23]的 expectedT, E 是它的完全体——还能带上失败原因。❓ Q7为什么 map 用 pair 而不是专门的 Entry 类型✅ 历史与通用性pair 提供了二元组 全套比较 结构化绑定的零成本通用件map/set 全系列复用它做 value_type代价是 first/second 无语义——所以遍历推荐用结构化绑定起好名字。九、总结速查表考点一句话结论三兄弟pair 两个 / tuple 多个 / optional 一个或没有访问.first/.secondgeti()* / value_or解包演进下标 → tie → 结构化绑定tie 独有复用旧变量 ignore比较字典序sort 直接可用空解引用* 是 UBvalue() 抛异常vs 指针值语义无借用/拥有歧义延迟初始化成员 optional emplace多返回值二元 pair / 多元 struct / 可空 optionaloptional 大小内联 标志零堆分配一句话回顾pair 装两个、tuple 装多个、optional 装一个或没有——共性是值语义自动拷贝、自动析构、不涉所有权解包用[C17]结构化绑定tie 只剩复用旧变量表达可能没有用 optional 而不是指针或魔法值空解引用是 UB、value_or兜底——返回值选型一句话二元 pair、多元 struct、可空 optional。如果您觉得本篇内容对你有帮助欢迎点赞 、收藏 ⭐、转发 。下期我们继续标准库篇——聊聊 std::any 与 std::variant开集的类型擦除和闭集的多选一怎么选、visit 与 overload 惯用法怎么写敬请关注

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价