为什么reinterpret_cast不强制copy_n相同大小类型之间的转换?
Why Doesn't reinterpret_cast Force copy_n for Casts between Same-Sized Types?
根据cppreference.com,reinterpret_cast
:
通过重新解释基础位模式在类型之间进行转换。
但等等,这是一个谎言,因为它只在这些情况下有效:
当指向类型
T1
的对象的指针或引用是指向不同类型T2
的对象的指示器或引用的reinterpret_cast
(或C样式转换)时,转换总是成功的,但是,只有当T1
和T2
都是标准布局类型并且以下情况之一为真时,才能访问结果指针或引用:
T2
是对象的(可能是cv限定的)动态类型T2
和T1
都是指向同一类型T3
的指针(可能是多级的,可能是在每个级别限定的cv)T2
是对象的动态类型的有符号或无符号变体(可能是cv限定的)T2
是一个聚合类型或并集类型,它将上述类型之一作为元素或非静态成员(递归地包括子聚合的元素和所包含并集的非静态数据成员):这使得从结构的第一个成员和从并集的一个元素强制转换到包含它的结构/并集是安全的T2
是对象的动态类型的基类(可能是cv限定的)T2
是char
或unsigned char
根据这份名单,一个非法的例子是:
auto foo = 13LL;
auto bar = reinterpret_cast<double&>(foo);
因此,唯一可以接受的方法是复制内存:
auto foo = 13LL;
double bar;
copy_n(reinterpret_cast<char*>(&foo), sizeof(foo), reinterpret_cast<char*>(&bar));
我的问题是,为什么reinterpret_cast
不为我处理这个问题?或者还有其他东西可以让我不必跳过这个环吗?
为什么
reinterpret_cast
不帮我处理呢?
一个原因是没有指定大小、对齐方式和位表示,所以这样的转换是不可移植的。然而,这并不能真正证明定义行为,而只是定义实现。
通过使其未定义,编译器可以假设不相关类型的表达式不会访问同一对象,这可以实现更好的优化。例如,在以下内容中:
int & i = something();
float & f = something_else();
const int i1 = i;
f = 42;
const int i2 = i;
编译器可以假设i1
和i2
都具有相同的值(i
通过对f
的赋值而保持不变)并将它们优化为单个常数。打破这种假设会导致不明确的行为。
或者还有其他东西可以让我不必跳过这个环吗?
复制字节是将一个对象类型重新解释为不相关类型的唯一定义良好的方法。
与reinterpret_cast
或并集别名有时可能会起作用(假设大小等匹配),但如果优化器对未定义的行为过于聪明,则可能会让您绊倒。
主要是由于对reinterpret_cast
的限制(cpprreference站点未完全捕获)
- 对齐问题和
- 陷阱表示
对于一个假设的reinterpret_cast
到数值,可以通过截断或零扩展轻松处理不同的大小,因为无论如何都会进入危险的比特级区域,所以这不是问题。
通过使用memcpy
或copy_n
,您可以解决对齐问题,但您仍然可能是陷阱表示的受害者。这意味着对结果值的使用可能会爆炸。在某些平台上,为了某些价值观。
请注意,标准对任何东西的保证都可以并且通常由任何特定的编译器扩展。
通常情况下,以比仅依赖标准的便携性低一点为目标是一个好主意。
例如,当你不能假设一个字节是8位时,事情会很快变得复杂。做出这种假设会降低可移植性。但受支持的平台仍然很大。
- 调用具有未标识类型的类的方法
- C++ 中模板化类型的类层次结构
- 根据模板类型选择类模板的成员类型?
- C++从抽象类型定义类成员
- 实例化具有不完整类型的类模板格式不正确(如果该类型是在之后定义的)
- 重载模板<类型名...>类的函数模板
- 在设计方面:重载vector类型的类成员的插入运算符
- 错误:使用 SWIG 的未知类型名称"类"
- 添加字符串类型的类成员会导致调用基类函数而不是子函数
- 包装任意类型/非类型模板类的模板类
- 使用相同方法但不同成员类型构建类的最佳方法
- 如何删除类内类类型的类成员指针
- 为什么我不能在同一行中定义两个相同类型的类的成员指针
- 如何仅从类类型推断类构造函数参数的类型
- 为什么要返回对小类成员的 const 引用?
- (C++);动态决定函数的类型(派生类)
- 具有容器变量类型的类模板
- 如何基于模板参数类型施放类模板
- 包含仅移动类型的类的构造函数应通过引用还是通过右值引用接收仅移动类型?
- 无法将类型为"类名 &"的非常量左值引用绑定到类型为"类名"的右值