【问题标题】:How could one copy union simple members with memcpy?如何使用 memcpy 复制联合简单成员?
【发布时间】:2019-12-30 09:32:50
【问题描述】:

我不太确定关于 memcpyunion 琐碎成员的标准引用。

考虑代码:

struct Test{
    union
    {
        void(*function_p)(void*);
        void(*function_p_c)(const void*);
    };
    Test(const Test &other)
    {
        using std::memcpy;
        memcpy(&function_p, &other.function_p, sizeof(function_p)); //?
        memcpy(&function_p_c, &other.function_p_c, sizeof(function_p_c)); //??
    }
};

int main(void)
{
    Test t1; t1.function_p = NULL; //let it be NULL for c++98 sake
    Test t2(t1); // is it safe? does this set new active member of union?

    return 0;
}

所以一个问题导致另一个问题:

  • 上面的代码安全吗?还是第二个/第一个 memcpy 的 UB 取决于哪个 union 成员用户已触摸?为两个成员都调用memcpy 是不是有点矫枉过正?

  • 如果它不安全,那么我如何在没有一些 flag-of-active-union-member 的情况下实现复制构造函数?

【问题讨论】:

  • 注意:我只是添加了language-lawyer标签,这是这种问题的习惯。由于最多有五个标签,因此我选择了std 来删除。
  • 为什么?为什么不直接使用=
  • 使用指定的工会成员,你可以做一个memcpy
  • 或者创建两个类TestATestB,一个有一个成员function_p,另一个有function_p_c。 - 你说你想“没有一些活跃工会成员的旗帜”。如果你没有那种标志,你将如何在课堂的其他地方使用正确的函数指针?
  • 取决于联合内的类型,但在你的情况下,是的。

标签: c++ language-lawyer std unions standards-compliance


【解决方案1】:

你用两个 memcpy 做的是未定义的行为。

union 仅与容纳其最大数据成员所需的一样大。 其他数据成员被分配在相同的字节中作为它的一部分 最大的成员。该分配的详细信息是 实现定义,并且从 不是最近编写的工会成员。 许多编译器 实现,作为非标准语言扩展,阅读能力 工会的非活跃成员。

other 只有function_p 处于活动状态,第二个内存复制触发未定义的行为。

【讨论】:

  • memcpy'ed 成员是否被视为“书面”?
  • @AlexanderG。似乎有一个关于这个问题的公开辩论。 stackoverflow.com/q/39763548/10933809。您需要一种簿记机制来了解活动类型或先初始化一个成员(因此使其处于活动状态),然后再进行 memcpy
  • @AlexanderG。您可以关注 Jarod42 评论。或者如果 C++17 是一个选项,请使用 std::variant 而不是 union。
【解决方案2】:

由于两个联合成员在内存中占用相同的空间,第二个 memcpy 将覆盖第一个。

【讨论】:

  • @Oblivion 我没有投反对票,但这个答案没有回答 OP 提出的任何问题。
  • @mch 我同意它没有回答。但我相信发表评论有助于改善帖子
猜你喜欢
  • 2021-11-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-28
  • 2015-07-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多