关于libstdc++中std::any小对象访问用const实现的疑问
问题
在查看libstdc的std::any实现时,发现针对小对象通过aligned_storage进行访问的代码使用了const修饰,这令人困惑。请问这样实现的目的是什么?是否与aligned_storage可能存储const对象有关?若如此,C标准中何处有相关依据?
对应的核心代码片段如下:
static _Tp* _S_access(const _Storage& __storage) { // The contained object is in __storage._M_buffer const void* __addr = &__storage._M_buffer; return static_cast<_Tp*>(const_cast<void*>(__addr)); }
回答
1. const修饰参数的核心目的
这个设计是为了复用同一份访问逻辑,同时兼容const和非const的std::any实例:
- 当调用
std::any_cast<const T>(const std::any&)时,传入的内部_Storage是const的,这个函数可以直接处理; - 当调用
std::any_cast<T>(std::any&)时,非const的_Storage可以隐式转换为const _Storage&,无需额外写一份非const版本的访问函数。
这里的const_cast是安全的:
- 如果原始
std::any是非const的,_Storage本身就是可修改的,const_cast只是去掉了临时的const限定,不会触发未定义行为; - 如果原始
std::any是const的,std::any_cast只会返回const T*或const T&,外部无法通过const接口修改对象,内部的非const指针不会被用来做非法修改。
2. 和存储const对象无关
std::any不会存储const对象——当你把const T放入std::any时,它实际存储的是T类型的对象(const限定会被剥离),因为std::any的构造函数会对传入参数进行拷贝/移动,拷贝const T得到的是普通的T实例。
3. C++标准的相关依据
const_cast的合法场景:C标准[expr.const.cast]章节明确,当原始对象本身是非const的,去掉const限定是合法操作;只有当原始对象是const的,通过const_cast修改才会触发未定义行为。libstdc的实现通过外部std::any_cast的接口区分了const/非const场景,保证了const_cast的安全性。std::any_cast的行为要求:标准规定std::any_cast<const T>(const std::any&)必须返回const引用/指针,std::any_cast<T>(std::any&)返回非const引用/指针,这个实现完全贴合标准的行为定义。
内容的提问来源于stack exchange,提问作者minex
相关产品推荐
相关产品推荐

