首页 > 解决方案 > 除了 memcpy,bit_cast 还会有哪些额外的 UB(如果有的话)?

问题描述

我有一个类,其目的是将可能具有对齐限制的数据移入或移出数据未对齐的序列化内存缓冲区。我已按如下方式设置和获取处理程序:

#include <cstring>
template<typename T>
struct handle_type {    
    static inline T get(const void *data) {
        T value;
        memcpy(&value, data, sizeof(T));
        return value;
    }
    static inline void set(void *data, T value) {
        memcpy(data, &value, sizeof(T));
    }
};

c++20出来后,我希望它会变成下面这样:

#include <bit>
template<typename T>
struct handle_type {    
    union unaligned { char bytes[sizeof(T)];  }; // EDIT: changed from struct
    static inline T get(const void *data) {
        return std::bit_cast<T>(*(const unaligned*)data);
    }
    static inline void set(void *data, T value) {
        *(unaligned *)data = std::bit_cast<unaligned>(value);
    }
};

它会起作用吗?或者我使用的是 inerim 类型,未对齐的结构类型,是否容易造成问题?

标签: c++c++20type-punning

解决方案


get除非用户提供了指向unaligned对象的指针,否则您的函数是 UB。你的set函数同样是 UB,除非data是一个unaligned对象。这些情况中的任何一种都违反了严格的别名。请记住:严格的别名后门是关于实际的char*;这与恰好包含char*.

此外,set可能是编译错误,完全取决于 的实现是否unalignedT. 毕竟,unaligned最后可能有填充。

bit_cast希望主要处理对象,而不是随机的内存缓冲区。为此,您应该坚持使用memcpy.


<改为使用union而不是struct>

那没有任何改变;使用 aunion并不能保证 的大小union等于其最大数据成员的大小。来自 [class.union]/2:

联合的大小足以包含其最大的非静态数据成员。

重点补充:“足够”,而不是“等于”。该标准允许实现使联合大于其最大数据成员的能力,因为这样的大小仍然是“足够的”。


推荐阅读