C++ std::any
一、基本概念
std::any 也是 C++17 引入的一个核心容器类。如果说 std::variant 是“类型安全的共用体(Union)”,那么 std::any 就是“类型安全的 void\* 指针”。
它能够存储任意类型的单个值,并且在运行时保留该值的类型信息,确保在取出数据时进行强类型检查。
在 C++17 之前,如果你需要一个可以接收“任何类型”的容器,通常只能用 void*。但 void* 极其危险:
- 类型不安全:你可以把
int的指针强转为void*,然后再强转成double*取出来,编译器不会报错,但这会导致严重的内存损坏和未定义行为。 - 生命周期管理困难:
void*不知道自己指向的对象何时该析构,容易导致内存泄漏。
std::any 完美解决了这些痛点:它既能存任何类型,又保证了类型安全和自动内存管理(RAII)。
二、基本用法
声明、初始化与修改:
1 | |
类型检查与安全取出值,要获取 std::any 内部的值,必须使用 std::any_cast:
1 | |
获取类型信息:
1 | |
三、variant 与 any
这两者都是 C++17 的类型安全容器,但设计哲学截然不同。
| 维度 | std::variant |
std::any |
|---|---|---|
| 类型限定 | 闭集:必须在编译期列出所有可能类型(如 variant) |
开集:可存任何类型,无需预先声明 |
| 内存分配 | 完全在栈上,无动态内存开销 | 可能触发堆分配(大对象时) |
| 类型检查 | 编译期配合 std::visit 可确保处理所有情况 |
运行期通过 any_cast 手动检查 |
| 访问效率 | 极高(接近原生类型) | 较低(有 RTTI 和指针间接开销) |
| 适用场景 | 状态机、多类型返回值、解析器结果 | 配置文件解析、通用事件派发、插件系统 |
四、注意
为了避免频繁的动态内存(堆)分配,绝大多数标准库实现对 std::any 使用了小对象优化:
- 如果存储的对象体积较小(通常等于或小于 2 到 3 个指针的大小,例如
int、double、std::string_view、或者只有几个字段的小struct),std::any会将对象直接存储在栈上的内部缓冲区中。 - 如果存储的对象体积较大(例如大
struct、较大的std::array),std::any会在堆上分配内存来存储该对象,并在内部保留一个指向堆内存的指针。
性能开销:
- 动态内存分配:对于大对象,每次赋值/拷贝都会触发
new/delete,开销较大。 - 运行时类型信息 (RTTI) 虚表开销:
std::any内部包含一个函数指针或虚表指针,用于在运行时管理对象的拷贝、移动和析构。因此,调用any_cast和析构时会存在间接寻址开销。 - 不能内联:编译器很难对
std::any的类型转换进行内联优化。
C++ std::any
http://example.com/2026/06/05/C++-std-any/