C++17 optional/variant/any三种容器对比
请对比C++17引入的std::optional(可能包含或不包含值)、std::variant(类型安全的联合体)和std::any(类型擦除容器)的设计目的、使用场景、性能开销及典型示例。
回答
小字辈
std::optional:表示可能包含T值或不包含(空状态)。
- 常用于:可能失败的函数返回值、可选参数。
- 访问:
*o(需确保有值,否则UB)、o.value()、o.value_or(default)、o.has_value()。 - 性能:占用sizeof(T)+1字节(bool标记),无堆分配。
std::optional<int> parse(const std::string& s);
std::variant<Types...>:类型安全的联合体,存储Types之一。
- 替代C union和void*,运行时通过index()判断当前类型。
- 访问:
std::get<T>(v)(值不对则抛bad_variant_access)、std::visit(visitor, v)。 - 性能:占用sizeof(largest T)+开销,无堆分配。
std::variant<int, double, std::string> v = "hello";
std::visit([](auto&& arg) { std::cout << arg; }, v);
std::any:完全类型擦除的容器(可持有任意类型)。
- 底层使用小对象优化(SSO),小类型放栈上,大类型堆分配。
- 访问:
std::any_cast<T>(a)(类型不对抛bad_any_cast)。 - 性能:有类型擦除开销(虚函数+可能堆分配)。
std::any a = 42;
a = std::string("hello");
int val = std::any_cast<int>(a); // 抛出异常