修改FlatBuffer顶层结构末尾元素时,能否避免反序列化子表?
修改FlatBuffer顶层结构末尾元素时,能否避免反序列化子表?
当然可以!你这个需求非常合理——FlatBuffer本身的设计就考虑到了这种“部分更新”的场景,完全不用把整个子表都反序列化再重新构建,直接复用原有子表的字节就行。
先给你直接上符合你需求的代码,再慢慢解释细节:
const auto* current = GetAlphabet(raw_data); flatbuffers::FlatBufferBuilder builder; // 复用原Alpha子表的字节,生成新builder中的偏移 const flatbuffers::Table* alpha_table = current->alpha(); const size_t alpha_size = flatbuffers::GetSize(alpha_table); flatbuffers::Offset<Alpha> alpha_offset; builder.StartTable(); // 直接复制原table的所有字节到新builder中 builder.PushBytes(reinterpret_cast<const uint8_t*>(alpha_table), alpha_size); alpha_offset = flatbuffers::Offset<Alpha>(builder.EndTable()); // 对Beta子表做同样的操作 const flatbuffers::Table* beta_table = current->beta(); const size_t beta_size = flatbuffers::GetSize(beta_table); flatbuffers::Offset<Beta> beta_offset; builder.StartTable(); builder.PushBytes(reinterpret_cast<const uint8_t*>(beta_table), beta_size); beta_offset = flatbuffers::Offset<Beta>(builder.EndTable()); // 最后创建新的Alphabet,用复用的子表偏移和新的字符串 auto new_comment = builder.CreateString("NewString"); auto new_alphabet = CreateAlphabet(builder, alpha_offset, beta_offset, new_comment); builder.Finish(new_alphabet);
为什么这么做可行?核心原因是FlatBuffer的Table结构是自包含的:每个Table都带自己的vtable(虚表),记录了字段的偏移信息,只要你的Schema没有修改过(比如Alpha和Beta的字段、顺序都没变),直接复制整个Table的字节到新的缓冲区里,它依然是一个合法的FlatBuffer Table。
不过有几个关键注意事项,一定要记牢:
- Schema必须完全兼容:如果原FlatBuffer的Alpha/Beta子表和你新构建用的Schema有差异(比如加了字段、改了字段顺序),直接复制字节会导致新的FlatBuffer损坏,读取时会出问题。
- 原缓冲区生命周期要稳定:在复制子表字节的时候,原
raw_data数组必须还在内存中,不能提前释放,否则会读到无效内存。 - 避免混用Struct和Table:如果你的Alpha/Beta是Struct(内联结构),那操作更简单,直接传原指针就行,但它们是Table的话,必须用上面的方式复制整个Table的字节——因为Table是在缓冲区中单独分配的,原指针在新的builder里无效。
这种方式的优势很明显:跳过了子表的反序列化和重新序列化过程,对于大型子表来说,能省不少内存和CPU时间,完全符合你想要的“只改顶层字符串,复用子表”的需求。
内容来源于stack exchange
相关产品推荐
相关产品推荐

