不能直接用void实现Any,因为void不管理对象生命周期、丢失const限定、无法复制非平凡类型、导致多态切片,而std::any通过类型擦除+函数指针表(vtable)实现值语义的安全存储与取值。

为什么不能直接用 void* 实现 Any
用 void* 存原始指针看似简单,但会立刻掉进生命周期和类型擦除的坑里:对象析构没人管、const 限定丢失、无法复制非 trivial 类型(比如 std::string)、多态类型切片。C++ 的 Any 必须管理值语义,不是指针语义。
核心是 type-erased storage + vtable 模式
标准库 std::any 的实现思路很清晰:每个 Any 对象内部持有一个指向“操作表”的指针(vtable),以及一块对齐的内存缓冲区(in-place 或 heap-allocated)。所有类型共用这套接口,不暴露具体类型。
-
std::any默认使用 small buffer optimization(SBO):小对象(如int、std::string短字符串)存栈上,大对象才 new - vtable 至少包含:
clone(拷贝构造)、destroy(析构)、get_type(返回std::type_info&)、compare(可选) - 构造时根据类型大小选择存储策略;赋值/移动需触发对应 vtable 函数
如何安全地取出值:type_id 检查 + reinterpret_cast 不行
不能靠 reinterpret_cast 强转——类型信息已擦除,运行时无保障。必须依赖 std::type_info 或 std::type_index 做运行时比对。
-
std::any_cast<t>(any_obj)</t>先调用any_obj.type() == typeid(T),失败则抛std::bad_any_cast - 成功后,通过 vtable 的偏移或指针算出实际对象地址,再用
static_cast转为T*(不是reinterpret_cast) - 对 const 重载要单独处理:vtable 需支持 const/non-const 两套函数指针
示例错误写法:*(int*)any_storage_ptr —— 若实际存的是 double,结果未定义;正确路径是走 vtable 的取值函数。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
立即学习“C++免费学习笔记(深入)”;
自己实现时最容易漏掉的三件事
很多手写 Any 在测试边缘 case 时崩,往往栽在这几个点上:
- 移动构造/赋值后原对象必须置为 empty 状态(
has_value() == false),否则析构两次 - 对
const T&构造,vtable 的clone必须能正确调用T的拷贝构造(而非默认构造+赋值) - 对 union 类型(如
std::monostate)或空基类,alignof和sizeof计算要严谨,否则 SBO 缓冲区对齐失败导致 UB
真正难的不是存,而是让每种类型在构造、拷贝、移动、析构、比较时都走对路径——漏一个函数指针,就等于给用户埋个 crash 点。

















