C++中any类型怎么用_C++17存储任意类型变量方法【进阶】

1次阅读

std::any是c++17引入的类型擦除容器,用于安全持有运行时类型不确定但需类型安全的任意可复制/移动值;适用于插件传参、配置解析等场景,禁用于同类型高频存储或替代variant/void*。

C++中any类型怎么用_C++17存储任意类型变量方法【进阶】

std::any 是什么,什么时候该用它

std::any 是 C++17 引入的类型擦除容器,用来安全地持有任意可复制(或可移动)类型的值。它不是万能替代 void*union工具,而是为“运行时类型不确定、但需严格类型安全”的场景设计的——比如插件系统传参、配置项解析、反射辅助结构。

常见错误现象:用 std::any 存大量同类型数据(如一 int),结果性能暴跌、代码冗长;或者没检查就直接 any_cast,触发 std::bad_any_cast 异常。

  • 它内部用小对象优化(SOO),小类型(如 intbool)通常不堆分配
  • 不支持不完整类型、抽象类、数组类型(如 int[5])、带删除拷贝/移动的类型
  • 不能直接比较两个 std::any 是否“逻辑相等”,需手动取出后比

怎么存、取、判断类型——三个核心操作

存值很简单:std::any 构造函数emplace 都支持:

std::any a = 42;                    // 推导为 int std::any b = std::String("hello");   // 推导为 std::string std::any c; c.emplace(3.1415);         // 显式指定类型并就地构造

取值必须用 std::any_cast,且有三种写法:

立即学习C++免费学习笔记(深入)”;

  • std::any_cast(any_obj):返回 T&,失败抛 std::bad_any_cast
  • std::any_cast(&any_obj):返回 T*,失败返回 nullptr(推荐用于不确定类型时)
  • std::any_cast(std::move(any_obj)):用于移动语义提取(原 any 置为空)

判断类型是否匹配,别用 type().name() 字符串比较(不可靠、平台相关),而应:

if (a.type() == typeid(std::string)) { ... }  // ✅ 安全 if (a.type() == typeid(int)) { ... }          // ✅

容易踩的坑:空值、移动后状态、异常安全

std::any 可以为空(默认构造),此时调用 type() 返回 typeid(void)any_cast 会失败:

  • 检查是否为空:用 a.has_value(),不要只靠 type() != typeid(void)
  • 移动赋值后,源 std::any 变为空:std::any x = 100; std::any y = std::move(x);x.has_value()false
  • any_cast 抛异常是标准行为,生产环境别裸 throw,尤其在循环或回调中

性能影响明显:每次 any_cast 都要运行时比对 type_info,比 std::variant 的编译期分支慢一个数量级。如果可能的类型集合固定且有限(如只有 int/double/std::string),优先用 std::variant

和 std::variant、void* 的关键区别在哪

std::anystd::variant 都是类型安全的泛型容器,但设计目标完全不同:

  • std::variant:编译期已知所有可能类型,内存布局紧凑,无堆分配,访问快,支持 std::visit
  • std::any:运行期任意类型,类型集完全开放,适合插件、脚本桥接等无法预知类型的场景

void* 相比:std::any 自动管理生命周期、支持移动语义、类型信息不丢失、不会因误 cast 导致 UB —— 但它不能跨 DLL 边界传递(RTTI 和 type_info 实现依赖编译器与链接方式),这点常被忽略。

text=ZqhQzanResources