为了序列化游戏中的组件,我需要能够仅在给定指针和大小的情况下访问各种向量中的数据。
如果我只有一个指向向量的void *,我想从向量中获取data()指针。我正在尝试从std::vector<T>
转换为std::vector<char>
以获取data()指针。我想知道以下代码是否已定义为行为,并且在不同情况下不会有所不同。
#include <iostream>
#include <vector>
int main()
{
std::vector<int> ints = { 0, 1, 2, 3, 4 };
std::vector<char>* memory = reinterpret_cast<std::vector<char>*>(&ints);
int *intArray = reinterpret_cast<int *>(memory->data());
std::cout << intArray[0] << intArray[1] << intArray[2] << intArray[3] << intArray[4] << std::endl; //01234 Works on gcc and vc++
std::getchar();
}
这似乎在这种孤立的情况下有效,但是我不知道它是否会在序列化代码内提供错误或未定义的行为。
答案 0 :(得分:0)
这是别名冲突:
std::vector<char>* memory = reinterpret_cast<std::vector<char>*>(&ints);
int *intArray = reinterpret_cast<int *>(memory->data());
每个[basic.life],在此处访问memory->data()
的行为都未定义。
解决此问题的方法是调用ints.data()
以获取指向基础连续数组的int*
指针。之后,您可以将其强制转换为void*
,char*
或unsigned char*
(或C ++ 17中的std::byte*
)。
您可以从那里回退到int*
以再次访问元素。
答案 1 :(得分:0)
我不认为这是UB。
使用reinterpret_cast<std::vector<char>*>(&ints)
,您正在将一个矢量对象转换为另一个不同(实际上是不兼容)类型的矢量对象。但是,您不必取消对结果指针的引用,并且-由于两个向量对象很可能具有相同的别名限制-强制转换就可以了。 cf,例如this在线C ++草案)。请注意,向量不会“就地”存储数据类型,但会保留指向值的指针。
5.2.10重新解释演员表
(7)可以将对象指针显式转换为的对象指针 70是当“指向T1的指针”类型的prvalue v为 转换为类型“ cv T2的指针”的类型,如果T1和T2均为标准布局,则结果为static_cast(static_cast(v)) 类型([basic.types])和T2的对齐要求不是 比T1严格,或者两种类型都无效。转换一个 将“指向T1的指针”类型的prvalue转换为“指向T2的指针”类型的prvalue(其中T1 和T2是对象类型,并且T2的对齐要求是 不严格于T1)并返回其原始类型 原始指针值。任何其他此类指针的结果 转换未指定。
因此,在此处前后投射矢量对象应该以定义的方式工作。
第二,您转换了一个指针,该指针最初指向(并别名为)int
“返回”为其原始类型int
。因此,显然不违反别名。
我在这里看不到任何UB(除非矢量对象具有比矢量对象更严格的别名规则,这很可能不是这种情况)。