贝利信息

C++类型安全进阶:span、expected与variant替代裸指针【现代C++范式】

日期:2026-01-22 00:00 / 作者:穿越時空
std::span 能安全替代 T* + size_t,因其将指针与长度绑定为不可分割的视图,不拥有数据、避免拷贝,且在编译期或运行时捕获尺寸错误与生命周期问题。

为什么 std::span 能安全替代 T* + size_t 参数对

裸指针加长度的组合在函数接口中极易引发越界、悬空或生命周期不匹配问题,std::span 把二者绑定为一个不可分割的视图对象,且不拥有数据——既避免拷贝开销,又强制调用方明确传递有效范围。

常见错误现象:process(arr, n)n 传错、arr 已析构、arr 实际长度小于 n;而 process(std::span(arr, n)) 在编译期就能捕获多数尺寸不匹配(如数组字面量推导),运行时构造失败也会触发断言(取决于实现)。

std::expectedstd::optional 或异常更适合哪些错误场景

std::expect

ed 明确区分「成功值」和「可预期的错误原因」,适用于错误可分类、需透传上下文、且不希望用异常打断控制流的场合(如解析配置、系统调用封装、异步 I/O 结果)。

对比:std::optional 只能表达“有/无”,无法携带错误信息;抛异常在性能敏感路径或禁用异常的环境(嵌入式、游戏引擎)中不可行。

何时该用 std::variant 而不是虚函数或多态指针

当类型集合固定、数量有限、且操作集中在单个函数内(如序列化、比较、格式化),std::variant 比虚函数更高效:无虚表查表、无动态内存分配、编译期确定布局;它天然支持访问者模式,也更容易做 constexpr 计算。

典型误用:std::variant<:unique_ptr>, std::shared_ptr> —— 这反而引入间接和堆分配,失去 variant 的优势。

裸指针还没彻底淘汰?这些边界情况仍需谨慎处理

现代 C++ 并未禁止裸指针,而是限制其使用范围:new/delete 配对、C API 交互、低层内存管理(如自定义 allocator)、以及某些模板元编程技巧中仍会见到。关键在于——裸指针只应出现在你**明确承担全部生命周期责任**的地方。

容易被忽略的点:std::spanstd::string_view 都不保证底层内存对齐;若对接 SIMD 或硬件寄存器映射,仍需用 alignas + 原始指针,并手动校验地址。