Hi John,
You have to copy into a new message, as you have done.
The reason is, the message tree pointed to by the AnyPointer is not necessarily contiguous in memory. Unlike most other serialization out there, Cap'n Proto objects point to their child objects using pointers that can cross over other object in between. (Most serializations use nested encoding instead, but this doesn't work well with zero-copy.) Generally, objects will be ordered in memory in the order in which they were allocated. Typically programs writing a message will work on one part of the tree at a time, in which case you'll get a depth-first ordering, but that's not guaranteed. If a program switches back and forth between building different parts of the message, the objects will end up interleaved in memory.
So the only way to get an object tree into contiguous memory is to copy it into a new arena -- i.e. a new MessageBuilder.
You could, however, avoid the second copy implied by `messageToFlatArray()`. Instead, before making the copy, use `getMsg().targetSize().wordCount` to see how much memory the message tree takes. Add 1 word for the root pointer. Then pass this to MallocMessageBuilder's constructor as the first segment size. Now copy the message. If you then call messageBuilder.getSegmentsForOutput(), you should find there is only one segment, containing the root pointer followed by the content. So now you can use that data without making an extra copy...
-Kenton