std::any

你可以把它想象成 C 语言中 void* 的高级类型安全版本。与 void* 不同的是,std::any 会记得它存储的到底是什么类型,并在你尝试错误地获取数据时抛出异常。


1. 基本用法

要使用 std::any,你需要包含头文件 <any>

#include <iostream>
#include <any>
#include <string>

int main() {
   // 1. 存储任意类型
   std::any a = 42;             // 存储 int
   a = 12.34;                   // 现在存储 double
   a = std::string("Hello");    // 现在存储 std::string

   // 2. 检查是否有值
   if (a.has_value()) {
       // 3. 获取存储的具体类型
       std::cout << "类型名称: " << a.type().name() << std::endl;
  }

   // 4. 类型安全地获取值 (std::any_cast)
   try {
       std::string s = std::any_cast<std::string>(a);
       std::cout << "值: " << s << std::endl;
  } catch (const std::bad_any_cast& e) {
       std::cout << "类型转换失败: " << e.what() << std::endl;
  }

   // 5. 清空内容
   a.reset();
   return 0;
}

2. 核心特性

特性说明
类型安全如果尝试用错误的类型进行 std::any_cast,会抛出 std::bad_any_cast 异常(或返回 nullptr 指针版本)。
值语义std::any 拷贝时会拷贝其内部存储的对象。
动态内存管理它可以处理各种大小的对象,较小的对象通常会触发“小对象优化”(SBO),而较大的对象会在堆上分配内存。
生命周期管理std::any 被销毁时,它会自动调用内部存储对象的析构函数。

3. std::any vs std::variant

这是一个常见的疑问,选择建议如下:

  • 使用 std::variant 的场景:如果你预先知道可能存储的类型范围(例如只能是 intfloat),std::variant 性能更高(无动态内存分配)且更安全。
  • 使用 std::any 的场景:如果你完全无法预知未来可能存储的类型,或者需要高度解耦的插件式架构时,使用 std::any

4. 性能提示

虽然 std::any 很强大,但它有一定的开销:

  1. 类型信息开销:由于要维护 typeid 信息。
  2. 动态内存分配:存储大型对象时会涉及堆分配。
  3. 转换开销std::any_cast 需要在运行时进行类型检查。

发表评论