向量之间的转换是否定义了行为?

时间:2019-01-21 18:30:07

标签: c++ visual-c++ language-lawyer stdvector undefined-behavior

为了序列化游戏中的组件,我需要能够仅在给定指针和大小的情况下访问各种向量中的数据。

如果我只有一个指向向量的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();
}

这似乎在这种孤立的情况下有效,但是我不知道它是否会在序列化代码内提供错误或未定义的行为。

2 个答案:

答案 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(除非矢量对象具有比矢量对象更严格的别名规则,这很可能不是这种情况)。