I am new to flatbuffers, and I assume that I'm doing something wrong, but I was definitely surprised by the following behavior.
I was looking at how the buffers are formatted on the wire and had a schema like:
table Inside {
b:string;
c:string;
}
table Object {
a:string;
i:Inside;
d:string;
}
root_type Object;
file_identifier "OBJT";
I was surprised that when I built Object in order, the "a" element was lost:
using namespace flatbuffers;
FlatBufferBuilder fbb;
ObjectBuilder ob(fbb);
ob.add_a(fbb.CreateString("A"));
InsideBuilder ib(fbb);
ib.add_b(fbb.CreateString("B"));
ib.add_c(fbb.CreateString("C"));
ob.add_i(ib.Finish());
ob.add_d(fbb.CreateString("D"));
FinishObjectBuffer(fbb, ob.Finish());
// code below this point will be the same for all examples
const uint8_t *buf = fbb.GetBufferPointer();
const size_t size = fbb.GetSize();
Verifier verifier(buf, size);
if (!VerifyObjectBuffer(verifier)) {
throw std::runtime_error{"Invalid buffer!"};
}
// macro to make it easier to print the flatbuffer::String objects
#define PP(str) str ? str->c_str() : "empty"
const Object *obj = GetObject(buf);
if (obj) {
printf("A = %s\n", PP(obj->a()));
if (obj->i()) {
printf("B = %s\n", PP(obj->i()->b()));
printf("C = %s\n", PP(obj->i()->c()));
} else {
printf("Inner struct missing\n");
}
printf("D = %s\n", PP(obj->d()));
} else {
printf("Object missing\n");
}
Output:
A = empty
B = B
C = C
D = D
If I move the add_a() line to after adding i then it works:
FlatBufferBuilder fbb;
ObjectBuilder ob(fbb);
InsideBuilder ib(fbb);
ib.add_b(fbb.CreateString("B"));
ib.add_c(fbb.CreateString("C"));
ob.add_i(ib.Finish());
ob.add_a(fbb.CreateString("A"));
ob.add_d(fbb.CreateString("D"));
FinishObjectBuffer(fbb, ob.Finish());
Output:
A = A
B = B
C = C
D = D
If add a and d first, then I lose both of the elements:
FlatBufferBuilder fbb;
ObjectBuilder ob(fbb);
ob.add_a(fbb.CreateString("A"));
ob.add_d(fbb.CreateString("D"));
InsideBuilder ib(fbb);
ib.add_b(fbb.CreateString("B"));
ib.add_c(fbb.CreateString("C"));
ob.add_i(ib.Finish());
FinishObjectBuffer(fbb, ob.Finish());
Output:
A = empty
B = B
C = C
D = empty
This behavior is fine, but I didn't see it documented anywhere, and it is a little strange that the verifier returns true on this buffer (though it is true that this buffer can be read safely). So, is this intended behavior, or I am doing something wrong?
-Peter