【问题标题】:Is it safe to reinterpret_cast<const char*> any struct that starts with a char[size] member?reinterpret_cast<const char*> 任何以 char[size] 成员开头的结构是否安全?
【发布时间】:2021-05-16 12:15:17
【问题描述】:

假设我有 2 个不同的结构:

struct A {
    char a_name[512];
    ...              // A struct data
}

struct B {
    char b_name[256];
    ...              // B struct data
}

给定std::string name,我需要检查容器中是否存在对象(无论是A 还是B)。由于AB 都以char[size] 成员开头,这是我要比较的名称,我尝试了以下操作:

// T is a template parameter which is always an object of type A or B
           ↓ 
for (const T& item : container)
    if (name == reinterpret_cast<const char*>(&item))

它确实按预期工作。我读该对象时好像它是一个字符数组,但由于A.a_nameB.b_name 保证为空终止,所以我不读我不应该读的内容……还是我读?上面的代码会产生未定义的行为吗?它会产生我没有考虑到的任何错误吗?如果是这样,我该如何处理这项任务?

我无法修改AB。我选择不为每个类重载 operator==,因为 AB 实际上是更多不同的结构,它们具有我上面描述的结构(char[size] + 更多数据)。

【问题讨论】:

  • 什么是T?貌似A和B没有共同的基类,所以不可能T
  • 重新打开问题,因为重复显然是错误的。它指出了一个问题,该问题询问 reinterpret_casting 到非 char* 类型,这会产生很大的不同。
  • // T is an object of type A or B ??为何如此?您正在处理的实际容器类型是什么?
  • @ChrisDodd T 表示模板函数的类型,而不是父类什么的。 A 和 B 除了第一个成员 char[] 之外完全不相关
  • @SergeyA 谢谢你重新打开它,我很困惑 ^^"。容器是std::vector&lt;T&gt;,而 T 是模板参数。如果这样我可以提供更多的代码更清楚

标签: c++ undefined-behavior reinterpret-cast


【解决方案1】:

如果您的类是标准布局类,您的代码应该是安全的。

在 [class.members] 部分的末尾,我们有

如果标准布局类对象有任何非静态数据成员,则其地址与其第一个非静态数据成员的地址相同(如果该成员不是位域)。 ... [注意:对象和它的第一个子对象是指针互转换的]

关于复合类型的部分,[basic.compound],说

如果两个对象是pointer-interconvertible,那么它们具有相同的地址,并且可以通过reinterpret_cast从一个指向另一个的指针中获得一个指向另一个的指针。

但是,您可以完全摆脱 reinterpret_cast,方法是创建一个帮助函数来返回正确的字段。

const char *GetName(const A &a) {
    return a.a_name;
}

const char *GetName(const B &b) {
    return b.b_name;
}
// ...
for (const T& item : container)
    if (name == GetName(item))

对此有一些变体,包括 GetName 开始一个返回特定字段的模板函数,以及具有不同字段名称的类型的特定实现。

【讨论】:

    猜你喜欢
    • 2012-10-24
    • 1970-01-01
    • 2012-11-16
    • 2017-01-18
    • 2016-01-23
    • 2021-10-31
    • 1970-01-01
    • 2013-07-15
    • 2014-12-10
    相关资源
    最近更新 更多