std::any支持任意可复制类型但需显式类型转换,std::variant更安全高效但类型列表须编译期确定,自定义类型擦除易出错,应优先使用标准库实现。

std::any 能存任意类型,但得手动取值
直接用 std::any 是最轻量的方案,它内部用类型擦除实现,支持所有可复制(copyable)类型。但它不提供自动类型转换——存进去什么,取出来必须用 std::any_cast 显式指定类型,否则抛 std::bad_any_cast。
常见错误是忘了检查类型是否匹配:
std::any x = 42; int v = std::any_cast<int>(x); // ✅ 正确 double w = std::any_cast<double>(x); // ❌ 抛异常
- 取值前建议先用
x.type() == typeid(int)判断 -
std::any不支持移动语义优化(C++17 后部分改进),频繁存取小类型有开销 - 不能直接比较两个
std::any是否“逻辑相等”,需自行判断类型再比值
std::variant 更安全,但类型列表必须编译期确定
如果你知道可能存的类型集合(比如只可能是 int、std::string 或 nullptr_t),std::variant<int, std::string, std::nullptr_t> 比 std::any 更高效、更安全:访问时类型错误会在编译期报错(用 std::get<T>),或运行时报 std::bad_variant_access(用 std::get<index> 或 visitor)。
典型误用是试图塞入未声明的类型:
立即学习“C++免费学习笔记(深入)”;
std::variant<int, double> v = "hello"; // ❌ 编译失败
- 类型列表不能含重复类型(
std::variant<int, int>不合法) - 含引用类型需用
std::reference_wrapper包裹(std::variant<int&>错误,应写std::variant<std::reference_wrapper<int>>) - 访问推荐用
std::visit+ lambda,避免多次std::holds_alternative判断
自己写类型擦除容器?别绕过 std::any 的实现细节
有人想手写类似 AnyContainer 来控制内存布局或加调试信息,但容易踩坑:类型删除(type erasure)需要正确处理构造、析构、拷贝/移动,还要对齐和分配策略。标准库的 std::any 已覆盖绝大多数场景,除非你明确需要定制行为(比如禁止动态分配、强制栈存储),否则没必要重造。
- 若真要自定义,核心是封装一个虚函数表(vtable)结构体,包含
destroy、copy、move等函数指针 - 切忌在析构函数里漏调用原始类型的析构器——这是最常见的崩溃原因
- 不要尝试用
void*直接存对象并手动调用构造函数:缺少异常安全保证,且无法处理带 non-trivial 析构的类型
什么时候该选 vector<std::any> 而不是 map<string, std::any>?
取决于你是否需要键名查找。如果只是按顺序存一堆异构值(比如解析 JSON 数组),std::vector<std::any> 足够;如果要按字段名查(如 JSON 对象),用 std::map<std::string, std::any> 或更高效的 std::unordered_map。
-
std::map插入时会按 key 排序,若不需要排序,优先选std::unordered_map - key 用
std::string_view可避免临时字符串构造,但注意生命周期——确保 view 所指内容比 map 存活得久 - 大量插入后做批量读取,考虑预分配 bucket 数(
reserve())提升unordered_map性能
真正麻烦的是嵌套:比如 std::any 里再存一个 std::vector<std::any>,这时类型检查和递归访问逻辑就得自己组织清楚——标准库不帮你做这层抽象。


















