将包含 POD 的包装器结构数组转换为它包含的 POD 类型数组是不是合法?

Posted

技术标签:

【中文标题】将包含 POD 的包装器结构数组转换为它包含的 POD 类型数组是不是合法?【英文标题】:Is it legal to cast array of wrapper structs containing POD to the array of POD type it contains?将包含 POD 的包装器结构数组转换为它包含的 POD 类型数组是否合法? 【发布时间】:2021-12-22 11:57:32 【问题描述】:

这个 C++ 代码是有效的还是未定义的行为?这个想法是能够将您无法控制的 POD 包装到另一个结构中以提供辅助功能,但仍然能够像使用原始 POD 一样使用它。

struct Data

  ...//POD
;
struct Wrapper

  Data data;//contains only this
  void HelperFuncA();
  void HelperFuncB();
  ...//only member functions
;

...
//is this legal?
std::vector<Wrapper> vec_of_wrappers;
Data* array_of_data = reinterpret_cast<Data*>(vec_of_wrappers.data());

【问题讨论】:

不,这是无效的。永远不要多态地处理数组。 这绝对是非法的。你怎么能确定编译器不会向Wrapper 类型的对象添加一些填充(或者,实际上,Data 出现在开头)? 如果是vec_of_wrappers(1),那么它在某些系统上可能是有效的,否则data()就是nullptr @PaulSanders 在第一个元素之前永远不会有填充,这是标准保证的。该代码由于其他原因是非法的(请参阅我的回答) Data* array_of_data = reinterpret_cast&lt;Data*&gt;(vec_of_wrappers.data()); 是未定义行为的开始(对于实际 UB,您需要取消引用 array_of_data),因为上述代码中不存在 reinterpret_cast 的允许转换。请参阅上述链接中的类型别名部分。 【参考方案1】:

现在,此代码无效。有几个原因。首先,将指向结构的第一个成员的指针转换为结构本身违反了严格的别名规则。您可以通过将Wrapper 设为Data 的子类来解决此问题。

第二个问题更成问题,因为您正试图以多态方式处理数组(在本例中为向量)。 sizeof Datasizeof Wrapper 不同,因此尝试索引 Wrapper 元素的数组,就好像它是 Data 元素的数组一样,最终会指向数组的随机区域。

【讨论】:

sizeof Data 和没有虚函数的sizeof Wrapper 一样吗? “首先,将指向结构第一个成员的指针转换为结构本身违反了严格的别名规则”Not really。 但指向 C 结构的指针与其第一个成员 one 具有相同的值 @n.1.8e9-where's-my-sharem。他的意思是类可能是 @n.1.8e9-where's-my-sharem。是的,但仍然不是:eel.is/c++draft/basic.lval#11 可互换指针在这里也不例外。

以上是关于将包含 POD 的包装器结构数组转换为它包含的 POD 类型数组是不是合法?的主要内容,如果未能解决你的问题,请参考以下文章

将结构化 numpy 数组(包含子数组)转换为 pandas 数据帧

没有泛型参数的反射转换为类型

p/invoke 方法返回空结构

Swig:将成员变量(指向值的指针)转换为 python 列表

这种解析器设计模式叫啥?使用包含关键字和函数指针的结构数组的解析器?

对象包装器与自动装箱