为什么不 reinterpret_cast 强制 copy_n 用于相同大小类型之间的转换?

2021-12-31 00:00:00 复制 binary casting c++ reinterpret-cast

根据cppreference.com,reinterpret_cast:

通过重新解释底层位模式在类型之间进行转换.

Converts between types by reinterpreting the underlying bit pattern.

但是等等,那是谎言,因为它只在这些情况下有效:

But wait, that's a lie cause it only works in these cases:

当对 T1 类型的对象的指针或引用是 reinterpret_cast(或 C 风格的强制转换)到不同类型的对象的指针或引用时 T2,转换总是成功,但只有当 T1T2 都是标准布局类型和以下之一时,才能访问结果指针或引用为真:

  • T2 是对象的(可能是 cv 限定的)动态类型
  • T2T1 都是(可能是多级的,可能在每一级都有 cv 限定)指向同一类型 T3
  • T2 是对象动态类型的(可能是 cv 限定的)有符号或无符号变体
  • T2 是聚合类型或联合类型,它将上述类型之一作为元素或非静态成员(递归地包括子聚合的元素和非静态数据成员)包含联合):这使得从结构的第一个成员和联合的元素转换为包含它的结构/联合是安全的.
  • T2 是对象的动态类型的(可能是 cv 限定的)基类
  • T2charunsigned char
  • When a pointer or reference to object of type T1 is reinterpret_cast (or C-style cast) to a pointer or reference to object of a different type T2, the cast always succeeds, but the resulting pointer or reference may only be accessed if both T1 and T2 are standard-layout types and one of the following is true:

    • T2 is the (possibly cv-qualified) dynamic type of the object
    • T2 and T1 are both (possibly multi-level, possibly cv-qualified at each level) pointers to the same type T3
    • T2 is the (possibly cv-qualified) signed or unsigned variant of the dynamic type of the object
    • T2 is an aggregate type or a union type which holds one of the aforementioned types as an element or non-static member (including, recursively, elements of subaggregates and non-static data members of the contained unions): this makes it safe to cast from the first member of a struct and from an element of a union to the struct/union that contains it.
    • T2 is a (possibly cv-qualified) base class of the dynamic type of the object
    • T2 is char or unsigned char

    根据该列表,非法示例是:

    According to that list an illegal example would be:

    auto foo = 13LL;
    auto bar = reinterpret_cast<double&>(foo);
    

    所以唯一可以接受的方式是复制内存:

    So the only acceptable way to make that cast is to copy the memory:

    auto foo = 13LL;
    double bar;
    
    copy_n(reinterpret_cast<char*>(&foo), sizeof(foo), reinterpret_cast<char*>(&bar));
    

    我的问题是,为什么 reinterpret_cast 不为我处理?或者还有其他可用的东西,所以我不必跳过这个箍?

    My question is, why doesn't reinterpret_cast handle that for me? Or is there something else available so I don't have to jump through this hoop?

    推荐答案

    为什么 reinterpret_cast 不为我处理?

    一个原因是没有指定大小、对齐方式和位表示,所以这样的转换是不可移植的.然而,这并不能真正证明使行为未定义,而只是实现定义.

    One reason is that the size, alignment, and bit representations aren't specified, so such a conversion wouldn't be portable. However, that wouldn't really justify making the behaviour undefined, just implementation-defined.

    通过将其设为 undefined,编译器可以假设无关类型的表达式不会访问同一个对象,这样可以进行更好的优化.例如,在以下内容中:

    By making it undefined, the compiler is allowed to assume that expressions of unrelated types don't access the same object, which can allow better optimisation. For example, in the following:

    int   & i = something();
    float & f = something_else();
    
    const int i1 = i;
    f = 42;
    const int i2 = i;
    

    编译器可以假设 i1i2 都具有相同的值(i 被赋值给 f),并将它们优化为一个常量.打破假设将导致未定义的行为.

    the compiler can assume that i1 and i2 both have the same value (i being unchanged by the assignment to f), and optimise them into a single constant. Breaking the assumption will then cause undefined behaviour.

    或者还有其他可用的东西,所以我不必跳过这个箍?

    Or is there something else available so I don't have to jump through this hoop?

    复制字节是将一种对象类型重新解释为不相关类型的唯一明确定义的方法.

    Copying the bytes is the only well-defined way to reinterpret one object type as an unrelated type.

    使用 reinterpret_cast 或联合别名有时可能会起作用(假设大小等匹配),但如果优化器对未定义的行为过于聪明,则可能会绊倒您.

    Aliasing with reinterpret_cast or a union might work sometimes (assuming the size etc. match), but might trip you up if the optimiser gets too clever with undefined behaviour.

相关文章