FlatBuffers C ++ reinterpret_cast访问实际上是未定义的行为吗?这样做真的可以吗?

最近,我尝试在C ++中使用FlatBuffers。我发现flatBuffers似乎在C ++中使用了很多类型的修饰,例如reinterpret_cast。这使我有些不舒服,因为我已经学会了it's undefined behavior in many cases

例如Rect在fbs文件中:

struct Rect {
    left:int;
    top:int;
    right:int;
    bottom:int;
}

变成此C ++代码以从表中读取它:

  const xxxxx::Rect *position() const {
    return GetStruct<const xxxxx::Rect *>(VT_POSITION);
  }

the definition of GetStruct仅使用reinterpret_cast。

我的问题是:

  1. 这是C ++中真正未定义的行为吗?
  2. 在实践中,这种用法实际上会出现问题吗?

更新:

缓冲区只能来自网络或磁盘。我不知道缓冲区是否实际上来自同一C ++程序的编写者编写的同一内存是否不同。

但是作者的自动生成方法是:

  void add_position(const xxxxx::Rect *position) {
    fbb_.AddStruct(Char::VT_POSITION,position);
  }

将使用this methodthis method,因此也使用reinterpret_cast。

zligy911 回答:FlatBuffers C ++ reinterpret_cast访问实际上是未定义的行为吗?这样做真的可以吗?

我没有分析整个FlatBuffers的源代码,但是我没有看到这些对象的创建位置:我看不到任何新表达式,它们会在此处创建P对象:

template<typename P> P GetStruct(voffset_t field) const {
    auto field_offset = GetOptionalFieldOffset(field);
    auto p = const_cast<uint8_t *>(data_ + field_offset);
    return field_offset ? reinterpret_cast<P>(p) : nullptr;
  }

所以,看来这段代码确实有未定义的行为。

但是,这仅适用于C ++ 17(或更低版本)。在C ++ 20中,将存在 implicit-lifetime 对象(例如,标量类型,聚合是隐式生命周期类型)。如果P具有隐式生存期,则可以很好地定义此代码。前提是同一类型始终访问相同的内存区域,而不会违反类型绑定规则(例如,始终由同一类型访问)。

,

我认为您的两个问题都将在Flatbuffers: Use in C++页上得到回答:

直接内存访问

从以上示例中可以看到,缓冲区中的所有元素都是通过生成的访问器访问的。这是因为所有内容都以小端格式存储在所有平台上(访问器在大端计算机上执行交换操作),并且因为用户通常不知道事物的布局。

对于结构,布局是确定性的,并保证在各个平台上都是相同的(标量与它们自己的大小对齐,并使其自身成为最大成员),并且可以使用sizeof()和memcpy指向结构,甚至是结构数组的指针。

这些段落保证-在给定有效的平面缓冲区后-所有内存访问均有效,因为该特定位置的内存将与预期的布局匹配。

如果要处理不受信任的平面缓冲区,则首先需要使用验证程序功能以确保平面缓冲区有效:

此验证程序将检查所有偏移量,字段的所有大小以及字符串的空终止,以确保访问缓冲区时,所有读取都将在缓冲区内结束。

本文链接:https://www.f2er.com/2368298.html

大家都在问