C++ STL之array、pair与tuple详解:从使用到底层,再到面试八股
本文面向面试和日常开发,先讲调用,再讲原理,最后给口语化面试答案。
一、用法速查
1.1 std::array
std::array 是一个固定大小的连续容器,大小必须在编译期确定。
cpp
#include <array>
// 定义:大小必须是编译期常量
array<int, 5> arr1 = {1, 2, 3, 4, 5};
array<int, 5> arr2{}; // 值初始化为 {0,0,0,0,0}
// 访问
arr1.at(2) = 10; // 越界检查,抛 out_of_range
arr1[3] = 20; // 不检查越界,越界 UB
arr1.front(); // 第一个元素
arr1.back(); // 最后一个元素
arr1.data(); // 返回 T* 原始指针,兼容 C 接口
// 操作
arr1.fill(0); // 全部置 0
// 大小与迭代
arr1.size(); // C++17 起 constexpr
arr1.begin(); // 迭代器,支持 range-for
arr1.end();
// C++11 ADL get<Index>
get<0>(arr1) = 100; // 编译期索引,越界编译报错
// range-for
for (auto &x : arr1)
cout << x << " ";
#mermaid-svg-ZM41qWLdM9PXkbXk{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ZM41qWLdM9PXkbXk .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ZM41qWLdM9PXkbXk .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ZM41qWLdM9PXkbXk .error-icon{fill:#552222;}#mermaid-svg-ZM41qWLdM9PXkbXk .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ZM41qWLdM9PXkbXk .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ZM41qWLdM9PXkbXk .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ZM41qWLdM9PXkbXk .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ZM41qWLdM9PXkbXk .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ZM41qWLdM9PXkbXk .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ZM41qWLdM9PXkbXk .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ZM41qWLdM9PXkbXk .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ZM41qWLdM9PXkbXk .marker.cross{stroke:#333333;}#mermaid-svg-ZM41qWLdM9PXkbXk svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ZM41qWLdM9PXkbXk p{margin:0;}#mermaid-svg-ZM41qWLdM9PXkbXk .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ZM41qWLdM9PXkbXk .cluster-label text{fill:#333;}#mermaid-svg-ZM41qWLdM9PXkbXk .cluster-label span{color:#333;}#mermaid-svg-ZM41qWLdM9PXkbXk .cluster-label span p{background-color:transparent;}#mermaid-svg-ZM41qWLdM9PXkbXk .label text,#mermaid-svg-ZM41qWLdM9PXkbXk span{fill:#333;color:#333;}#mermaid-svg-ZM41qWLdM9PXkbXk .node rect,#mermaid-svg-ZM41qWLdM9PXkbXk .node circle,#mermaid-svg-ZM41qWLdM9PXkbXk .node ellipse,#mermaid-svg-ZM41qWLdM9PXkbXk .node polygon,#mermaid-svg-ZM41qWLdM9PXkbXk .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ZM41qWLdM9PXkbXk .rough-node .label text,#mermaid-svg-ZM41qWLdM9PXkbXk .node .label text,#mermaid-svg-ZM41qWLdM9PXkbXk .image-shape .label,#mermaid-svg-ZM41qWLdM9PXkbXk .icon-shape .label{text-anchor:middle;}#mermaid-svg-ZM41qWLdM9PXkbXk .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ZM41qWLdM9PXkbXk .rough-node .label,#mermaid-svg-ZM41qWLdM9PXkbXk .node .label,#mermaid-svg-ZM41qWLdM9PXkbXk .image-shape .label,#mermaid-svg-ZM41qWLdM9PXkbXk .icon-shape .label{text-align:center;}#mermaid-svg-ZM41qWLdM9PXkbXk .node.clickable{cursor:pointer;}#mermaid-svg-ZM41qWLdM9PXkbXk .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ZM41qWLdM9PXkbXk .arrowheadPath{fill:#333333;}#mermaid-svg-ZM41qWLdM9PXkbXk .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ZM41qWLdM9PXkbXk .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ZM41qWLdM9PXkbXk .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ZM41qWLdM9PXkbXk .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ZM41qWLdM9PXkbXk .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ZM41qWLdM9PXkbXk .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ZM41qWLdM9PXkbXk .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ZM41qWLdM9PXkbXk .cluster text{fill:#333;}#mermaid-svg-ZM41qWLdM9PXkbXk .cluster span{color:#333;}#mermaid-svg-ZM41qWLdM9PXkbXk div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ZM41qWLdM9PXkbXk .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ZM41qWLdM9PXkbXk rect.text{fill:none;stroke-width:0;}#mermaid-svg-ZM41qWLdM9PXkbXk .icon-shape,#mermaid-svg-ZM41qWLdM9PXkbXk .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ZM41qWLdM9PXkbXk .icon-shape p,#mermaid-svg-ZM41qWLdM9PXkbXk .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ZM41qWLdM9PXkbXk .icon-shape .label rect,#mermaid-svg-ZM41qWLdM9PXkbXk .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ZM41qWLdM9PXkbXk .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ZM41qWLdM9PXkbXk .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ZM41qWLdM9PXkbXk :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} std::array<int,5>
栈上连续内存
编译期固定大小
无堆分配开销
支持 data() 获原始指针
size() 为 constexpr
性能等同原生数组
array 与 std::vector 最大区别:array 全在栈上,vector 的底层数据在堆上。
#mermaid-svg-CDLD67bNByM9X6jc{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-CDLD67bNByM9X6jc .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-CDLD67bNByM9X6jc .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-CDLD67bNByM9X6jc .error-icon{fill:#552222;}#mermaid-svg-CDLD67bNByM9X6jc .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-CDLD67bNByM9X6jc .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-CDLD67bNByM9X6jc .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-CDLD67bNByM9X6jc .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-CDLD67bNByM9X6jc .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-CDLD67bNByM9X6jc .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-CDLD67bNByM9X6jc .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-CDLD67bNByM9X6jc .marker{fill:#333333;stroke:#333333;}#mermaid-svg-CDLD67bNByM9X6jc .marker.cross{stroke:#333333;}#mermaid-svg-CDLD67bNByM9X6jc svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-CDLD67bNByM9X6jc p{margin:0;}#mermaid-svg-CDLD67bNByM9X6jc .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-CDLD67bNByM9X6jc .cluster-label text{fill:#333;}#mermaid-svg-CDLD67bNByM9X6jc .cluster-label span{color:#333;}#mermaid-svg-CDLD67bNByM9X6jc .cluster-label span p{background-color:transparent;}#mermaid-svg-CDLD67bNByM9X6jc .label text,#mermaid-svg-CDLD67bNByM9X6jc span{fill:#333;color:#333;}#mermaid-svg-CDLD67bNByM9X6jc .node rect,#mermaid-svg-CDLD67bNByM9X6jc .node circle,#mermaid-svg-CDLD67bNByM9X6jc .node ellipse,#mermaid-svg-CDLD67bNByM9X6jc .node polygon,#mermaid-svg-CDLD67bNByM9X6jc .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-CDLD67bNByM9X6jc .rough-node .label text,#mermaid-svg-CDLD67bNByM9X6jc .node .label text,#mermaid-svg-CDLD67bNByM9X6jc .image-shape .label,#mermaid-svg-CDLD67bNByM9X6jc .icon-shape .label{text-anchor:middle;}#mermaid-svg-CDLD67bNByM9X6jc .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-CDLD67bNByM9X6jc .rough-node .label,#mermaid-svg-CDLD67bNByM9X6jc .node .label,#mermaid-svg-CDLD67bNByM9X6jc .image-shape .label,#mermaid-svg-CDLD67bNByM9X6jc .icon-shape .label{text-align:center;}#mermaid-svg-CDLD67bNByM9X6jc .node.clickable{cursor:pointer;}#mermaid-svg-CDLD67bNByM9X6jc .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-CDLD67bNByM9X6jc .arrowheadPath{fill:#333333;}#mermaid-svg-CDLD67bNByM9X6jc .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-CDLD67bNByM9X6jc .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-CDLD67bNByM9X6jc .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-CDLD67bNByM9X6jc .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-CDLD67bNByM9X6jc .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-CDLD67bNByM9X6jc .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-CDLD67bNByM9X6jc .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-CDLD67bNByM9X6jc .cluster text{fill:#333;}#mermaid-svg-CDLD67bNByM9X6jc .cluster span{color:#333;}#mermaid-svg-CDLD67bNByM9X6jc div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-CDLD67bNByM9X6jc .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-CDLD67bNByM9X6jc rect.text{fill:none;stroke-width:0;}#mermaid-svg-CDLD67bNByM9X6jc .icon-shape,#mermaid-svg-CDLD67bNByM9X6jc .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-CDLD67bNByM9X6jc .icon-shape p,#mermaid-svg-CDLD67bNByM9X6jc .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-CDLD67bNByM9X6jc .icon-shape .label rect,#mermaid-svg-CDLD67bNByM9X6jc .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-CDLD67bNByM9X6jc .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-CDLD67bNByM9X6jc .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-CDLD67bNByM9X6jc :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} std::array<int,3> a
栈: 123
std::vector<int> v(3)
栈: 指针、大小、容量
堆: 123
1.2 std::pair
pair 把两个值打包成一个类型。
cpp
#include <utility> // pair 在 <utility> 中
// 构造
pair<int, string> p1(1, "one");
auto p2 = make_pair(2, "two"); // C++11 类型推导
pair<int, string> p3 = {3, "three"}; // C++11 花括号
// 访问
p1.first = 10;
p1.second = "ten";
// piecewise_construct:避免多余拷贝
struct Heavy {
Heavy(int, string) { /* 构造开销大 */ }
};
pair<Heavy, Heavy> pw(
piecewise_construct,
forward_as_tuple(1, "a"), // 直接在 pair 内构造
forward_as_tuple(2, "b")
);
// C++17 结构化绑定
auto [k, v] = p1; // k = p1.first, v = p1.second
piecewise_construct 的流程:
#mermaid-svg-zAj7pqLtwTffjXn0{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-zAj7pqLtwTffjXn0 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-zAj7pqLtwTffjXn0 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-zAj7pqLtwTffjXn0 .error-icon{fill:#552222;}#mermaid-svg-zAj7pqLtwTffjXn0 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-zAj7pqLtwTffjXn0 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-zAj7pqLtwTffjXn0 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-zAj7pqLtwTffjXn0 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-zAj7pqLtwTffjXn0 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-zAj7pqLtwTffjXn0 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-zAj7pqLtwTffjXn0 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-zAj7pqLtwTffjXn0 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-zAj7pqLtwTffjXn0 .marker.cross{stroke:#333333;}#mermaid-svg-zAj7pqLtwTffjXn0 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-zAj7pqLtwTffjXn0 p{margin:0;}#mermaid-svg-zAj7pqLtwTffjXn0 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-zAj7pqLtwTffjXn0 .cluster-label text{fill:#333;}#mermaid-svg-zAj7pqLtwTffjXn0 .cluster-label span{color:#333;}#mermaid-svg-zAj7pqLtwTffjXn0 .cluster-label span p{background-color:transparent;}#mermaid-svg-zAj7pqLtwTffjXn0 .label text,#mermaid-svg-zAj7pqLtwTffjXn0 span{fill:#333;color:#333;}#mermaid-svg-zAj7pqLtwTffjXn0 .node rect,#mermaid-svg-zAj7pqLtwTffjXn0 .node circle,#mermaid-svg-zAj7pqLtwTffjXn0 .node ellipse,#mermaid-svg-zAj7pqLtwTffjXn0 .node polygon,#mermaid-svg-zAj7pqLtwTffjXn0 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-zAj7pqLtwTffjXn0 .rough-node .label text,#mermaid-svg-zAj7pqLtwTffjXn0 .node .label text,#mermaid-svg-zAj7pqLtwTffjXn0 .image-shape .label,#mermaid-svg-zAj7pqLtwTffjXn0 .icon-shape .label{text-anchor:middle;}#mermaid-svg-zAj7pqLtwTffjXn0 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-zAj7pqLtwTffjXn0 .rough-node .label,#mermaid-svg-zAj7pqLtwTffjXn0 .node .label,#mermaid-svg-zAj7pqLtwTffjXn0 .image-shape .label,#mermaid-svg-zAj7pqLtwTffjXn0 .icon-shape .label{text-align:center;}#mermaid-svg-zAj7pqLtwTffjXn0 .node.clickable{cursor:pointer;}#mermaid-svg-zAj7pqLtwTffjXn0 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-zAj7pqLtwTffjXn0 .arrowheadPath{fill:#333333;}#mermaid-svg-zAj7pqLtwTffjXn0 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-zAj7pqLtwTffjXn0 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-zAj7pqLtwTffjXn0 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-zAj7pqLtwTffjXn0 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-zAj7pqLtwTffjXn0 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-zAj7pqLtwTffjXn0 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-zAj7pqLtwTffjXn0 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-zAj7pqLtwTffjXn0 .cluster text{fill:#333;}#mermaid-svg-zAj7pqLtwTffjXn0 .cluster span{color:#333;}#mermaid-svg-zAj7pqLtwTffjXn0 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-zAj7pqLtwTffjXn0 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-zAj7pqLtwTffjXn0 rect.text{fill:none;stroke-width:0;}#mermaid-svg-zAj7pqLtwTffjXn0 .icon-shape,#mermaid-svg-zAj7pqLtwTffjXn0 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-zAj7pqLtwTffjXn0 .icon-shape p,#mermaid-svg-zAj7pqLtwTffjXn0 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-zAj7pqLtwTffjXn0 .icon-shape .label rect,#mermaid-svg-zAj7pqLtwTffjXn0 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-zAj7pqLtwTffjXn0 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-zAj7pqLtwTffjXn0 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-zAj7pqLtwTffjXn0 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 否
是
pair<Heavy, Heavy> p(...)
是否使用 piecewise_construct?
构造临时 Heavy 对象
拷贝/移动到 pair 中
两次构造 + 两次拷贝
传入 forward_as_tuple
直接在 pair 成员位置原地构造
零拷贝
1.3 std::tuple
tuple 是 pair 的泛化,可以装任意数量、任意类型的元素。
cpp
#include <tuple>
// 构造
tuple<int, string, double> t1(1, "hello", 3.14);
auto t2 = make_tuple(2, "world", 2.71);
// 访问:std::get<I> 编译期索引
get<0>(t1) = 42; // 修改第 0 个元素
cout << get<1>(t1); // 读第 1 个元素
// 用类型索引(要求类型唯一)
get<double>(t1) = 1.41;
// std::tie:解包到已有变量
int x; string s; double d;
tie(x, s, d) = t1; // x=42, s="hello", d=1.41
// C++17 结构化绑定
auto [a, b, c] = t1; // 更简洁
// std::apply:把 tuple 解包传给函数
auto f = [](int i, string s, double d) {
cout << i << s << d;
};
apply(f, t1); // 等价于 f(42, "hello", 1.41)
// tuple_cat:拼接 tuple
auto t3 = tuple_cat(t1, t2);
二、底层原理
2.1 array 的本质:C 数组的 STL 封装
std::array<T, N> 内部只有一块连续内存,没有堆分配。在 gcc 和 clang 中定义类似:
cpp
template <class T, size_t N>
struct array {
T elems[N]; // 唯一的成员
// ......迭代器、at、front、back 等都是对 elems 的操作封装
};
栈上分配意味着不需要手动释放,也不会有内存碎片。
与原生 T[N] 的关键区别:
| 维度 | T arr[N] |
std::array<T,N> |
|---|---|---|
| 传参 | 退化为指针,丢失大小信息 | 按值/引用传递,不退化 |
| 迭代器 | 无,只能用指针 | 有 begin/end,支持 STL 算法 |
| 越界检查 | 无 | at() 抛异常 |
size() |
无 | constexpr 大小 |
| 赋值 | 不支持 arr1 = arr2 |
支持 arr1 = arr2 |
| range-for | 支持(C++11 起) | 支持 |
2.2 pair 的本质
pair 就是一个简单的结构体,没有任何魔法:
cpp
template <class T1, class T2>
struct pair {
T1 first;
T2 second;
// 各种构造函数(默认、拷贝、移动、piecewise)
};
piecewise_construct 的原理 :如果不使用 piecewise_construct,构造 pair<T1,T2> 时 T1 和 T2 必须先构造出临时对象再拷贝/移动到 pair 中。使用 piecewise_construct + forward_as_tuple 后,pair 直接在成员位置上调用构造函数------没有临时对象,没有拷贝:
cpp
// 无 piecewise_construct:先构造临时 Heavy,再移动进 pair
pair<Heavy, Heavy> p1{Heavy(1,"a"), Heavy(2,"b")};
// 有 piecewise_construct:在 pair 内部原地构造
pair<Heavy, Heavy> p2(piecewise_construct,
forward_as_tuple(1, "a"), forward_as_tuple(2, "b"));
2.3 tuple 的编译期递归继承
tuple 不是用数组实现的------它在编译期就知道每个元素的类型和位置,靠的是模板元编程。
核心思想:递归继承 。tuple<A, B, C> 继承自 tuple<B, C>,tuple<B, C> 继承自 tuple<C>。每层基类存一个元素。
#mermaid-svg-nWthD27ywSfyYigZ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-nWthD27ywSfyYigZ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-nWthD27ywSfyYigZ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-nWthD27ywSfyYigZ .error-icon{fill:#552222;}#mermaid-svg-nWthD27ywSfyYigZ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-nWthD27ywSfyYigZ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-nWthD27ywSfyYigZ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-nWthD27ywSfyYigZ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-nWthD27ywSfyYigZ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-nWthD27ywSfyYigZ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-nWthD27ywSfyYigZ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-nWthD27ywSfyYigZ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-nWthD27ywSfyYigZ .marker.cross{stroke:#333333;}#mermaid-svg-nWthD27ywSfyYigZ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-nWthD27ywSfyYigZ p{margin:0;}#mermaid-svg-nWthD27ywSfyYigZ .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-nWthD27ywSfyYigZ .cluster-label text{fill:#333;}#mermaid-svg-nWthD27ywSfyYigZ .cluster-label span{color:#333;}#mermaid-svg-nWthD27ywSfyYigZ .cluster-label span p{background-color:transparent;}#mermaid-svg-nWthD27ywSfyYigZ .label text,#mermaid-svg-nWthD27ywSfyYigZ span{fill:#333;color:#333;}#mermaid-svg-nWthD27ywSfyYigZ .node rect,#mermaid-svg-nWthD27ywSfyYigZ .node circle,#mermaid-svg-nWthD27ywSfyYigZ .node ellipse,#mermaid-svg-nWthD27ywSfyYigZ .node polygon,#mermaid-svg-nWthD27ywSfyYigZ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-nWthD27ywSfyYigZ .rough-node .label text,#mermaid-svg-nWthD27ywSfyYigZ .node .label text,#mermaid-svg-nWthD27ywSfyYigZ .image-shape .label,#mermaid-svg-nWthD27ywSfyYigZ .icon-shape .label{text-anchor:middle;}#mermaid-svg-nWthD27ywSfyYigZ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-nWthD27ywSfyYigZ .rough-node .label,#mermaid-svg-nWthD27ywSfyYigZ .node .label,#mermaid-svg-nWthD27ywSfyYigZ .image-shape .label,#mermaid-svg-nWthD27ywSfyYigZ .icon-shape .label{text-align:center;}#mermaid-svg-nWthD27ywSfyYigZ .node.clickable{cursor:pointer;}#mermaid-svg-nWthD27ywSfyYigZ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-nWthD27ywSfyYigZ .arrowheadPath{fill:#333333;}#mermaid-svg-nWthD27ywSfyYigZ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-nWthD27ywSfyYigZ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-nWthD27ywSfyYigZ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-nWthD27ywSfyYigZ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-nWthD27ywSfyYigZ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-nWthD27ywSfyYigZ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-nWthD27ywSfyYigZ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-nWthD27ywSfyYigZ .cluster text{fill:#333;}#mermaid-svg-nWthD27ywSfyYigZ .cluster span{color:#333;}#mermaid-svg-nWthD27ywSfyYigZ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-nWthD27ywSfyYigZ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-nWthD27ywSfyYigZ rect.text{fill:none;stroke-width:0;}#mermaid-svg-nWthD27ywSfyYigZ .icon-shape,#mermaid-svg-nWthD27ywSfyYigZ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-nWthD27ywSfyYigZ .icon-shape p,#mermaid-svg-nWthD27ywSfyYigZ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-nWthD27ywSfyYigZ .icon-shape .label rect,#mermaid-svg-nWthD27ywSfyYigZ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-nWthD27ywSfyYigZ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-nWthD27ywSfyYigZ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-nWthD27ywSfyYigZ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} tuple<A,B,C>
tuple<B,C>
tuple<C>
值为 C
值为 B
值为 A
这就是 gcc/libstdc++ 的实现思路。MSVC 做了空基类优化(EBO)和扁平化存储,但对使用者透明。
std::get<I> 如何工作 ?核心是 this 指针的静态类型转换:
cpp
// 伪代码:
template <size_t I, class... Types>
constexpr auto &get(tuple<Types...> &t) noexcept {
using base_type = /* 第 I 层的基类类型 */;
return static_cast<base_type&>(t).value;
}
当调用 get<0>(t) 时,编译器推导出 base_type 是第一层对应的基类,把 this 从 tuple<A,B,C> 转型到第 0 层的基类上,访问该层存的那个 value。所有索引检查在编译期 完成------get<5>(tuple<int,int,int>{}) 直接编译失败,没有运行时开销。
std::get 的编译期索引流程:
#mermaid-svg-DoAuPnLgbaKPAp9v{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-DoAuPnLgbaKPAp9v .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-DoAuPnLgbaKPAp9v .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-DoAuPnLgbaKPAp9v .error-icon{fill:#552222;}#mermaid-svg-DoAuPnLgbaKPAp9v .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-DoAuPnLgbaKPAp9v .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-DoAuPnLgbaKPAp9v .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-DoAuPnLgbaKPAp9v .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-DoAuPnLgbaKPAp9v .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-DoAuPnLgbaKPAp9v .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-DoAuPnLgbaKPAp9v .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-DoAuPnLgbaKPAp9v .marker{fill:#333333;stroke:#333333;}#mermaid-svg-DoAuPnLgbaKPAp9v .marker.cross{stroke:#333333;}#mermaid-svg-DoAuPnLgbaKPAp9v svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-DoAuPnLgbaKPAp9v p{margin:0;}#mermaid-svg-DoAuPnLgbaKPAp9v .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-DoAuPnLgbaKPAp9v .cluster-label text{fill:#333;}#mermaid-svg-DoAuPnLgbaKPAp9v .cluster-label span{color:#333;}#mermaid-svg-DoAuPnLgbaKPAp9v .cluster-label span p{background-color:transparent;}#mermaid-svg-DoAuPnLgbaKPAp9v .label text,#mermaid-svg-DoAuPnLgbaKPAp9v span{fill:#333;color:#333;}#mermaid-svg-DoAuPnLgbaKPAp9v .node rect,#mermaid-svg-DoAuPnLgbaKPAp9v .node circle,#mermaid-svg-DoAuPnLgbaKPAp9v .node ellipse,#mermaid-svg-DoAuPnLgbaKPAp9v .node polygon,#mermaid-svg-DoAuPnLgbaKPAp9v .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-DoAuPnLgbaKPAp9v .rough-node .label text,#mermaid-svg-DoAuPnLgbaKPAp9v .node .label text,#mermaid-svg-DoAuPnLgbaKPAp9v .image-shape .label,#mermaid-svg-DoAuPnLgbaKPAp9v .icon-shape .label{text-anchor:middle;}#mermaid-svg-DoAuPnLgbaKPAp9v .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-DoAuPnLgbaKPAp9v .rough-node .label,#mermaid-svg-DoAuPnLgbaKPAp9v .node .label,#mermaid-svg-DoAuPnLgbaKPAp9v .image-shape .label,#mermaid-svg-DoAuPnLgbaKPAp9v .icon-shape .label{text-align:center;}#mermaid-svg-DoAuPnLgbaKPAp9v .node.clickable{cursor:pointer;}#mermaid-svg-DoAuPnLgbaKPAp9v .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-DoAuPnLgbaKPAp9v .arrowheadPath{fill:#333333;}#mermaid-svg-DoAuPnLgbaKPAp9v .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-DoAuPnLgbaKPAp9v .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-DoAuPnLgbaKPAp9v .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-DoAuPnLgbaKPAp9v .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-DoAuPnLgbaKPAp9v .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-DoAuPnLgbaKPAp9v .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-DoAuPnLgbaKPAp9v .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-DoAuPnLgbaKPAp9v .cluster text{fill:#333;}#mermaid-svg-DoAuPnLgbaKPAp9v .cluster span{color:#333;}#mermaid-svg-DoAuPnLgbaKPAp9v div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-DoAuPnLgbaKPAp9v .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-DoAuPnLgbaKPAp9v rect.text{fill:none;stroke-width:0;}#mermaid-svg-DoAuPnLgbaKPAp9v .icon-shape,#mermaid-svg-DoAuPnLgbaKPAp9v .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-DoAuPnLgbaKPAp9v .icon-shape p,#mermaid-svg-DoAuPnLgbaKPAp9v .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-DoAuPnLgbaKPAp9v .icon-shape .label rect,#mermaid-svg-DoAuPnLgbaKPAp9v .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-DoAuPnLgbaKPAp9v .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-DoAuPnLgbaKPAp9v .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-DoAuPnLgbaKPAp9v :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
否
get<1>(t)
编译器确定索引 I=1
推导第 1 层基类类型
static_cast 将 this 转型到对应基类
访问该层存储的 value
编译期完成全部检查
I 超出范围?
编译报错
生成零开销的访问代码
2.4 结构化绑定底层
C++17 结构化绑定:
cpp
auto [x, y] = p; // pair
auto [a, b, c] = t; // tuple
对 pair 和 tuple,它等价于:
cpp
// auto [x, y] = p ≈ auto __e = p; auto &x = get<0>(__e); auto &y = get<1>(__e);
注意这里 x 和 y 是引用 ------如果 p 是左值,x y 就是左值引用;如果 p 是右值,则是右值引用。对于 array 也是同样的 get 机制(array 有 ADL 的 std::get 重载)。
#mermaid-svg-G70mOmyEXUFvcg0z{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-G70mOmyEXUFvcg0z .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-G70mOmyEXUFvcg0z .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-G70mOmyEXUFvcg0z .error-icon{fill:#552222;}#mermaid-svg-G70mOmyEXUFvcg0z .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-G70mOmyEXUFvcg0z .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-G70mOmyEXUFvcg0z .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-G70mOmyEXUFvcg0z .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-G70mOmyEXUFvcg0z .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-G70mOmyEXUFvcg0z .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-G70mOmyEXUFvcg0z .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-G70mOmyEXUFvcg0z .marker{fill:#333333;stroke:#333333;}#mermaid-svg-G70mOmyEXUFvcg0z .marker.cross{stroke:#333333;}#mermaid-svg-G70mOmyEXUFvcg0z svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-G70mOmyEXUFvcg0z p{margin:0;}#mermaid-svg-G70mOmyEXUFvcg0z .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-G70mOmyEXUFvcg0z .cluster-label text{fill:#333;}#mermaid-svg-G70mOmyEXUFvcg0z .cluster-label span{color:#333;}#mermaid-svg-G70mOmyEXUFvcg0z .cluster-label span p{background-color:transparent;}#mermaid-svg-G70mOmyEXUFvcg0z .label text,#mermaid-svg-G70mOmyEXUFvcg0z span{fill:#333;color:#333;}#mermaid-svg-G70mOmyEXUFvcg0z .node rect,#mermaid-svg-G70mOmyEXUFvcg0z .node circle,#mermaid-svg-G70mOmyEXUFvcg0z .node ellipse,#mermaid-svg-G70mOmyEXUFvcg0z .node polygon,#mermaid-svg-G70mOmyEXUFvcg0z .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-G70mOmyEXUFvcg0z .rough-node .label text,#mermaid-svg-G70mOmyEXUFvcg0z .node .label text,#mermaid-svg-G70mOmyEXUFvcg0z .image-shape .label,#mermaid-svg-G70mOmyEXUFvcg0z .icon-shape .label{text-anchor:middle;}#mermaid-svg-G70mOmyEXUFvcg0z .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-G70mOmyEXUFvcg0z .rough-node .label,#mermaid-svg-G70mOmyEXUFvcg0z .node .label,#mermaid-svg-G70mOmyEXUFvcg0z .image-shape .label,#mermaid-svg-G70mOmyEXUFvcg0z .icon-shape .label{text-align:center;}#mermaid-svg-G70mOmyEXUFvcg0z .node.clickable{cursor:pointer;}#mermaid-svg-G70mOmyEXUFvcg0z .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-G70mOmyEXUFvcg0z .arrowheadPath{fill:#333333;}#mermaid-svg-G70mOmyEXUFvcg0z .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-G70mOmyEXUFvcg0z .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-G70mOmyEXUFvcg0z .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-G70mOmyEXUFvcg0z .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-G70mOmyEXUFvcg0z .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-G70mOmyEXUFvcg0z .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-G70mOmyEXUFvcg0z .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-G70mOmyEXUFvcg0z .cluster text{fill:#333;}#mermaid-svg-G70mOmyEXUFvcg0z .cluster span{color:#333;}#mermaid-svg-G70mOmyEXUFvcg0z div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-G70mOmyEXUFvcg0z .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-G70mOmyEXUFvcg0z rect.text{fill:none;stroke-width:0;}#mermaid-svg-G70mOmyEXUFvcg0z .icon-shape,#mermaid-svg-G70mOmyEXUFvcg0z .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-G70mOmyEXUFvcg0z .icon-shape p,#mermaid-svg-G70mOmyEXUFvcg0z .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-G70mOmyEXUFvcg0z .icon-shape .label rect,#mermaid-svg-G70mOmyEXUFvcg0z .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-G70mOmyEXUFvcg0z .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-G70mOmyEXUFvcg0z .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-G70mOmyEXUFvcg0z :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 结构化绑定 auto x,y = p
编译器生成隐藏变量 auto __e = p
auto &x = get<0>(__e)
auto &y = get<1>(__e)
x/y 是引用: 取决于 p 的左右值
三、面试题 + 口语化答案
Q1:array 和原生数组有什么区别?
"array 是 STL 封装,传参不退化、有迭代器、size() 是 constexpr、at() 带越界检查;原生数组传参退化为指针,没有 size() 没迭代器。array 的性能和数组一样(无堆分配)。"
Q2:std::array 的 size() 是 constexpr 吗?
"C++17 开始是 constexpr。因为 array 的大小是模板参数,编译期已知,所以 size() 在 C++17 做了 constexpr。C++17 前不是。"
Q3:array 的 data() 返回的指针什么时候失效?
"array 在栈上分配,指针在 array 对象生命周期内有效。array 离开作用域时栈内存自动回收,指针即失效。这和 vector 不同------vector 的 data() 在 vector 自身被销毁或重新分配时才失效。"
Q4:piecewise_construct 的作用?
"避免多余拷贝。对不可移动或拷贝成本高的类型,piecewise_construct + forward_as_tuple 直接在 pair 内部构造每个元素,不走临时对象再拷贝的路径。本质上是把构造函数参数传递给内部成员的位置。"
Q5:std::get<I> 为什么用 int 模板参数而不是运行时索引?
"因为 tuple 的底层是递归继承,每层存一个元素。索引 I 必须在编译期确定,编译器才能通过 static_cast 把 this 转型到正确的基类层上。运行时索引做不到这一点。可以用 std::variant 替代运行时类型不确定的场景。"
Q6:结构化绑定是引用还是拷贝?
"取决于声明方式:auto [x, y] = t 是拷贝(auto 推导出值类型);auto &[x, y] = t 是引用;const auto &[x, y] = t 是 const 引用。注意如果 t 是临时对象,引用版本会悬垂。"
Q7:std::apply 有什么用?
"把 tuple 的元素展开作为参数传给一个可调用对象。比如 apply(f, tuple(1, "hi", 3.14)) 等价于 f(1, "hi", 3.14)。底层靠 std::index_sequence 编译期生成参数包,再用 get<I> 依次取出元素作为实参。"
Q8:tuple 和 struct 怎么选?
"优先用 struct------字段有语义名字,可读性强。tuple 适合泛型编程、类型擦除(std::any 里存不同类型的 tuple)、或作为函数返回多个值的临时手段。一旦字段有业务含义,struct 是更好的选择。"
一句话总结 :array 是零堆开销的栈上连续容器,pair 的 piecewise_construct 能消除不必要拷贝,tuple 靠编译期递归继承实现任意数量元素的泛化 pair------面试重点在于递归继承如何支撑编译期索引、以及 piecewise_construct 避免拷贝的原理。