如何无需memcpy实现类型双关?类成员存地址的指针转换问题
问题分析与解决方案
首先明确核心问题:你混淆了变量自身的内存地址和变量存储的内容。
你的原代码逻辑是正确的:memcpy(&adress, &(this->failed), sizeof(void*)) 是把failed变量占用的字节(因为alignas(void*)保证它的大小和对齐都匹配void*)里存储的内容,复制到adress变量中,这个内容才是指向BaseA对象的地址。
而你尝试的错误写法:((BaseA*)&(this->failed))->failed,这里的&(this->failed)取的是failed这个bool变量自己的内存地址,把这个地址强制转换成BaseA*后访问failed成员,相当于去failed变量所在的内存位置找BaseA对象的failed成员,这和你实际想要的(读取failed变量里存的地址指向的BaseA对象)完全不是一回事,自然无法正常工作。
简洁的替代方案
方案1:使用reinterpret_cast直接解析变量内容
可以通过两次类型转换,直接读取failed变量存储的内容作为指针:
auto getFailed() { return reinterpret_cast<BaseA*>(*reinterpret_cast<void**>(&this->failed))->failed; }
- 第一步
reinterpret_cast<void**>(&this->failed):把bool*类型的指针转换成void**,解引用后就能得到failed变量存储的void*地址值。 - 第二步再把这个地址值转换成
BaseA*,最后访问目标对象的failed成员。
方案2:C++20及以上使用std::bit_cast(更安全)
如果项目支持C++20,推荐用std::bit_cast做类型转换,它能保证按字节复制,避免未定义行为:
#include <bit> auto getFailed() { void* target_addr = std::bit_cast<void*>(this->failed); return reinterpret_cast<BaseA*>(target_addr)->failed; }
std::bit_cast会直接把failed变量的字节内容转换成void*类型,效果和原代码的memcpy完全一致,但写法更简洁。
方案3:使用union(兼容旧标准)
如果需要兼容C++20之前的版本,也可以用union实现类型转换:
union BoolToPtr { bool b; void* ptr; }; auto getFailed() { BoolToPtr converter; converter.b = this->failed; return reinterpret_cast<BaseA*>(converter.ptr)->failed; }
利用union的特性,同一个内存区域可以用不同类型访问,同样能读取failed变量存储的地址值。
内容的提问来源于stack exchange,提问作者Paul Gigel
相关产品推荐
相关产品推荐

