【问题标题】:Is using memcpy to construct a trivially copyable union UB? Active member?正在使用 memcpy 构建一个可简单复制的联合 UB 吗?活跃成员?
【发布时间】:2021-11-09 06:11:58
【问题描述】:

我担心未定义的行为。您可以使用 memcpy 初始化一个可简单复制的联合类型的值吗?当我考虑将 Boost Serialization 与 BOOST_IS_BITWISE_SERIALIZABLE(MyUnionType) 一起使用时出现了这种情况,我假设它使用了 memcpy 之类的东西。

#include <cstring>

enum class Foo: int {};

union Bar {
    int num;
    Foo foo;
};

int baz(int src) {
    Bar dst;

    // My understanding is that memcpy does initialize dst
    // but doesn't set the active member of the union.
    std::memcpy(&dst, &src, sizeof(Bar));

    // My understanding is that whichever member is read
    // first here becomes the active member of the union.
    if (src > 42) {
        return dst.num;
    } else {
        return (int)dst.foo;
    }
}

【问题讨论】:

    标签: c++ initialization union undefined-behavior memcpy


    【解决方案1】:

    从定义上看,我认为这个案例没有问题:

    可平凡复制的类是这样的类(用类、结构或联合定义):

    • 使用隐式定义的复制和移动构造函数、复制和移动赋值以及析构函数。
    • 没有虚拟成员。
    • 它的基类和非静态数据成员(如果有)本身也是可简单复制的类型。

    会员终身 工会成员的生命周期从该成员被激活时开始。如果另一个成员之前处于活动状态,则其生命周期结束。

    在这种情况下,Foo 本身是可简单复制的

    static_assert(std::is_trivially_copyable_v<Bar>);
    

    所以我没有看到任何 UB 的理由

    【讨论】:

    • 让我警惕的是,我认为您只能阅读工会的活跃成员,通常是最后写入的成员。但是由于 memcpy 没有指定任何成员,因此此时不能有活动成员。这就是为什么我认为活动成员必须由在 memcpy 之后首先读取(或写入)哪个成员来确定。我没有看到standard 中提到的内容。
    • 从 c++17 标准中我看到了你的担忧T 类型的,构成对象的底层字节 (6.6.1) 可以复制到 char、unsigned char 或 std::byte (21.2.1) 的数组中。39 如果该数组的内容被复制回对象,该对象随后应保持其原始值。这意味着复制工会将保留它的状态,你很好。据我所知,memcpy 到工会成员的作用还没有定义
    猜你喜欢
    • 2019-12-30
    • 2015-07-18
    • 2021-12-26
    • 2015-10-02
    • 2023-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-30
    相关资源
    最近更新 更多