c++oding="utf-8" ?>
std::any能存可复制或可移动的完整类型(如int、std::string、自定义struct),不能存引用、数组、抽象类、不完整类型、void或删除/私有拷贝构造的类型;取值须用std::any_cast显式指定类型,否则抛std::bad_any_cast。

std::any能存什么,不能存什么
std::any 只能保存可复制(CopyConstructible)或可移动(MoveConstructible)的类型。空值、void、抽象类、带删除/私有拷贝构造函数的类型、不完整类型(如前置声明未定义的 class X;)都不能直接存进去。
常见误用是试图塞入数组类型(如 int[10])、C 风格字符串字面量("hello" 本质是 const char[6]),这些会编译失败——因为数组不可复制,字面量类型不可隐式转为 std::string。
- ✅ 能存:
int、std::string、std::vector<double></double>、自定义结构体(只要满足拷贝/移动要求) - ❌ 不能存:
int[5]、void、std::unique_ptr<int></int>(虽可移动,但std::any构造时默认尝试拷贝;需显式std::move)
怎么安全地存和取值
存值很简单:std::any 构造函数或 emplace 方法都能接受任意兼容类型。但取值必须显式指定类型,且运行时类型不匹配会抛出 std::bad_any_cast 异常——不是编译错误,容易漏测。
推荐先用 type() 检查再取,或用 std::any_cast<t></t> 的指针重载做“试探性取值”:
<pre class="brush:php;toolbar:false;">std::any a = 42;
if (a.type() == typeid(int)) {
int x = std::any_cast<int>(a); // 安全
}
// 或更轻量:
if (auto p = std::any_cast<int>(&a)) {
int x = *p; // 非空指针才取
}</int></int>
移动语义和性能要注意什么
std::any
int、std::shared_ptr)直接存栈上;大类型(如长 std::string 或大 std::vector)才会堆分配。但 SOO 阈值因标准库实现而异(libc++ 约 48 字节,MSVC 约 64 字节),不透明。
- 存大对象时,避免无谓拷贝:用
std::any{std::move(x)}替代std::any{x} - 取值后若原
std::any不再需要,可考虑std::move出来(std::any_cast<t>(std::move(a))</t>),但注意这会让a变为空 - 频繁存取同一类型?不如直接用
std::variant——零开销、类型安全、无异常风险
空值和重置的正确写法
std::any 默认构造即为空状态,但不能用 == nullptr 判断。检查是否为空,必须用 has_value()。
清空一个已含值的 std::any,不要赋值 std::any{}(虽可行但低效),应调用 reset():
<pre class="brush:php;toolbar:false;">std::any a = "hello";
a.reset(); // 推荐:明确语义,且可能避免临时对象构造
// a = std::any{}; // 不推荐:触发默认构造再赋值
重置后调用 std::any_cast
std::bad_any_cast,这点和空指针解引用一样危险——别跳过 has_value() 检查。
实际项目里,std::any 最适合配置项解析、插件系统参数传递这类“类型不确定但生命周期短”的场景。一旦类型集合可枚举,立刻换成 std::variant;一旦要跨线程共享或频繁访问,得考虑加锁或换更专用的数据结构。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











