获取当前对象地址转换为long类型的代码是否存在未定义行为(UB)?
首先给出明确结论:你的代码是**100%符合C++标准、可移植且无未定义行为(UB)**的,不过有个小细节可以优化得更严谨,下面一步步拆解每个部分的合法性:
1. std::addressof(*this) 在构造函数中的安全性
当进入类的构造函数体时,虽然对象还没完全构造完成(比如成员变量可能还未初始化),但对象的内存空间已经被成功分配,它的内存地址已经是确定的。std::addressof(*this) 是获取这个地址最稳妥的方式——它会直接返回对象的原始内存地址,完全不受类可能重载的operator&影响,这完全符合C++标准的规定,没有任何问题。
2. reinterpret_cast<intptr_t>(...) 的合法性
C标准明确规定:如果实现支持 std::intptr_t 类型(这是C11及以后标准库<cstdint>定义的有符号整数类型,目前所有主流平台都提供支持),那么任何对象指针都可以安全转换为std::intptr_t类型,并且如果把这个整数再转换回原指针类型,会得到和原指针完全一致的值。
这里的reinterpret_cast正是标准允许的用法:它专门负责在对象指针与足够容纳指针值的整数类型之间做双向转换,这个过程不存在未定义行为,是完全可移植的。
3. static_cast<long> 的注意事项
把intptr_t转换为long这一步,需要留意:在部分64位平台上,long可能是32位宽度,而intptr_t是64位,这时候转换会截断高位数值——不过这属于实现定义的行为,而非未定义行为。也就是说,编译器会按照自身规则处理转换(比如直接截断高位),不会出现崩溃或不可预测的UB。
如果想要彻底避免精度损失的风险,建议直接用std::intptr_t来存储和输出这个值,而非转成long,比如修改代码为:
std::cout << reinterpret_cast<std::intptr_t>(std::addressof(*this)) << '\n';
这样在所有支持C++11及以上的平台上都能做到完全可移植,不会有精度损失的问题。
总结
你原有的代码没有任何未定义行为,所有转换步骤都符合C++标准。reinterpret_cast在这里的使用是标准明确许可的指针与整数类型双向转换,而构造函数中获取*this的地址也是完全合法的——因为对象的内存已经分配完成,地址是确定的。
内容来源于stack exchange

