深入解析 C++17 中的 std::any 实现
在 C++17 标准中,std::any 提供了一种类型安全的方式来存储任意类型的值。它使用类型擦除(type erasure)技术实现,使得一个对象可以包含任何类型的值而不需要提前知道该类型。本文将详细解析 std::any 的内部实现原理。
一、类型擦除概念
类型擦除是指在运行时擦除类型信息,使得代码可以处理多种类型。std::any 使用类型擦除来存储任意类型的值,同时提供类型安全的访问方式。
二、std::any 的结构
std::any 的实现主要依赖于以下几个核心组件:
any类:主要的接口类,负责管理存储的值。any::placeholder类:一个抽象基类,用于定义存储值的通用接口。any::holder类:一个模板类,继承自placeholder,用于具体存储某种类型的值。
1. any 类
any 类是用户直接使用的接口类。它包含一个指向 placeholder 基类的指针,用于管理存储的值。
class any {
public:
any() noexcept : content(nullptr) {}
template<typename ValueType>
any(const ValueType& value)
: content(new holder<std::decay_t<ValueType>>(value)) {}
any(const any& other)
: content(other.content ? other.content->clone() : nullptr) {}
any(any&& other) noexcept : content(other.content) {
other.content = nullptr;
}
~any() { delete content; }
any& operator=(const any& other) {
if (this != &other) {
delete content;
content = other.content ? other.content->clone() : nullptr;
}
return *this;
}
any& operator=(any&& other) noexcept {
if (this != &other) {
delete content;
content = other.content;
other.content = nullptr;
}
return *this;
}
template<typename ValueType>
any& operator=(const ValueType& value) {
delete content;
content = new holder<std::decay_t<ValueType>>(value);
return *this;
}
bool has_value() const noexcept {
return content != nullptr;
}
const std::type_info& type() const noexcept {
return content ? content->type() : typeid(void);
}
private:
placeholder* content;
};
2. placeholder 类
placeholder 是一个抽象基类,定义了存储值的通用接口,包括获取类型信息和克隆自身的纯虚函数。
class placeholder {
public:
virtual ~placeholder() = default;
virtual const std::type_info& type() const noexcept = 0;
virtual placeholder* clone() const = 0;
};
3. holder 类
holder 类是一个模板类,继承自 placeholder,用于存储具体类型的值。它实现了 placeholder 的虚函数,包括获取类型信息和克隆自身。
template<typename ValueType>
class holder : public placeholder {
public:
holder(const ValueType& value) : held(value) {}
holder(ValueType&& value) : held(std::move(value)) {}
virtual const std::type_info& type() const noexcept override {
return typeid(ValueType);
}
virtual placeholder* clone() const override {
return new holder(held);
}
ValueType held;
};
三、std::any_cast 的实现
std::any_cast 是一个模板函数,用于从 any 对象中提取存储的值。它利用 dynamic_cast 来进行类型安全的转换。
1. 非指针版本
用于提取值的非指针版本:
template<typename ValueType>
ValueType any_cast(const any& operand) {
auto p = any_cast<std::decay_t<ValueType>>(&operand);
if (!p) throw bad_any_cast();
return *p;
}
template<typename ValueType>
ValueType any_cast(any& operand) {
auto p = any_cast<std::decay_t<ValueType>>(&operand);
if (!p) throw bad_any_cast();
return *p;
}
template<typename ValueType>
ValueType any_cast(any&& operand) {
auto p = any_cast<std::decay_t<ValueType>>(&operand);
if (!p) throw bad_any_cast();
return std::move(*p);
}
2. 指针版本
用于提取值的指针版本:
template<typename ValueType>
const ValueType* any_cast(const any* operand) noexcept {
if (operand && operand->type() == typeid(ValueType)) {
return &static_cast<any::holder<ValueType>*>(operand->content)->held;
}
return nullptr;
}
template<typename ValueType>
ValueType* any_cast(any* operand) noexcept {
if (operand && operand->type() == typeid(ValueType)) {
return &static_cast<any::holder<ValueType>*>(operand->content)->held;
}
return nullptr;
}
四、总结
std::any 是 C++17 提供的一种灵活且类型安全的存储和传递任意类型值的工具。通过类型擦除技术,std::any 可以在运行时存储和管理不同类型的值。理解其实现原理有助于我们更好地使用这一工具,并在需要时进行适当的性能优化。