1Use in C++ {#flatbuffers_guide_use_cpp} 2========== 3 4## Before you get started 5 6Before diving into the FlatBuffers usage in C++, it should be noted that 7the [Tutorial](@ref flatbuffers_guide_tutorial) page has a complete guide 8to general FlatBuffers usage in all of the supported languages (including C++). 9This page is designed to cover the nuances of FlatBuffers usage, specific to 10C++. 11 12#### Prerequisites 13 14This page assumes you have written a FlatBuffers schema and compiled it 15with the Schema Compiler. If you have not, please see 16[Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler) 17and [Writing a schema](@ref flatbuffers_guide_writing_schema). 18 19Assuming you wrote a schema, say `mygame.fbs` (though the extension doesn't 20matter), you've generated a C++ header called `mygame_generated.h` using the 21compiler (e.g. `flatc -c mygame.fbs`), you can now start using this in 22your program by including the header. As noted, this header relies on 23`flatbuffers/flatbuffers.h`, which should be in your include path. 24 25## FlatBuffers C++ library code location 26 27The code for the FlatBuffers C++ library can be found at 28`flatbuffers/include/flatbuffers`. You can browse the library code on the 29[FlatBuffers GitHub page](https://github.com/google/flatbuffers/tree/master/include/flatbuffers). 30 31## Testing the FlatBuffers C++ library 32 33The code to test the C++ library can be found at `flatbuffers/tests`. 34The test code itself is located in 35[test.cpp](https://github.com/google/flatbuffers/blob/master/tests/test.cpp). 36 37This test file is built alongside `flatc`. To review how to build the project, 38please read the [Building](@ref flatbuffers_guide_building) documenation. 39 40To run the tests, execute `flattests` from the root `flatbuffers/` directory. 41For example, on [Linux](https://en.wikipedia.org/wiki/Linux), you would simply 42run: `./flattests`. 43 44## Using the FlatBuffers C++ library 45 46*Note: See [Tutorial](@ref flatbuffers_guide_tutorial) for a more in-depth 47example of how to use FlatBuffers in C++.* 48 49FlatBuffers supports both reading and writing FlatBuffers in C++. 50 51To use FlatBuffers in your code, first generate the C++ classes from your 52schema with the `--cpp` option to `flatc`. Then you can include both FlatBuffers 53and the generated code to read or write FlatBuffers. 54 55For example, here is how you would read a FlatBuffer binary file in C++: 56First, include the library and generated code. Then read the file into 57a `char *` array, which you pass to `GetMonster()`. 58 59~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} 60 #include "flatbuffers/flatbuffers.h" 61 #include "monster_test_generate.h" 62 #include <iostream> // C++ header file for printing 63 #include <fstream> // C++ header file for file access 64 65 66 std::ifstream infile; 67 infile.open("monsterdata_test.mon", std::ios::binary | std::ios::in); 68 infile.seekg(0,std::ios::end); 69 int length = infile.tellg(); 70 infile.seekg(0,std::ios::beg); 71 char *data = new char[length]; 72 infile.read(data, length); 73 infile.close(); 74 75 auto monster = GetMonster(data); 76~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 77 78`monster` is of type `Monster *`, and points to somewhere *inside* your 79buffer (root object pointers are not the same as `buffer_pointer` !). 80If you look in your generated header, you'll see it has 81convenient accessors for all fields, e.g. `hp()`, `mana()`, etc: 82 83~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} 84 std::cout << "hp : " << monster->hp() << std::endl; // `80` 85 std::cout << "mana : " << monster->mana() << std::endl; // default value of `150` 86 std::cout << "name : " << monster->name()->c_str() << std::endl; // "MyMonster" 87~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 88 89*Note: That we never stored a `mana` value, so it will return the default.* 90 91The following attributes are supported: 92 93- `shared` (on a field): For string fields, this enables the usage of string 94 pooling (i.e. `CreateSharedString`) as default serialization behavior. 95 96 Specifically, `CreateXxxDirect` functions and `Pack` functions for object 97 based API (see below) will use `CreateSharedString` to create strings. 98 99## Object based API. {#flatbuffers_cpp_object_based_api} 100 101FlatBuffers is all about memory efficiency, which is why its base API is written 102around using as little as possible of it. This does make the API clumsier 103(requiring pre-order construction of all data, and making mutation harder). 104 105For times when efficiency is less important a more convenient object based API 106can be used (through `--gen-object-api`) that is able to unpack & pack a 107FlatBuffer into objects and standard STL containers, allowing for convenient 108construction, access and mutation. 109 110To use: 111 112~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} 113 // Autogenerated class from table Monster. 114 MonsterT monsterobj; 115 116 // Deserialize from buffer into object. 117 UnPackTo(&monsterobj, flatbuffer); 118 119 // Update object directly like a C++ class instance. 120 cout << monsterobj->name; // This is now a std::string! 121 monsterobj->name = "Bob"; // Change the name. 122 123 // Serialize into new flatbuffer. 124 FlatBufferBuilder fbb; 125 Pack(fbb, &monsterobj); 126~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 127 128The following attributes are specific to the object-based API code generation: 129 130- `native_inline` (on a field): Because FlatBuffer tables and structs are 131 optionally present in a given buffer, they are best represented as pointers 132 (specifically std::unique_ptrs) in the native class since they can be null. 133 This attribute changes the member declaration to use the type directly 134 rather than wrapped in a unique_ptr. 135 136- `native_default`: "value" (on a field): For members that are declared 137 "native_inline", the value specified with this attribute will be included 138 verbatim in the class constructor initializer list for this member. 139 140- `native_custom_alloc`:"custom_allocator" (on a table or struct): When using the 141 object-based API all generated NativeTables that are allocated when unpacking 142 your flatbuffer will use "custom allocator". The allocator is also used by 143 any std::vector that appears in a table defined with `native_custom_alloc`. 144 This can be used to provide allocation from a pool for example, for faster 145 unpacking when using the object-based API. 146 147 Minimal Example: 148 149 schema: 150 151 table mytable(native_custom_alloc:"custom_allocator") { 152 ... 153 } 154 155 with custom_allocator defined before flatbuffers.h is included, as: 156 157 template <typename T> struct custom_allocator : public std::allocator<T> { 158 159 typedef T *pointer; 160 161 template <class U> 162 struct rebind { 163 typedef custom_allocator<U> other; 164 }; 165 166 pointer allocate(const std::size_t n) { 167 return std::allocator<T>::allocate(n); 168 } 169 170 void deallocate(T* ptr, std::size_t n) { 171 return std::allocator<T>::deallocate(ptr,n); 172 } 173 174 custom_allocator() throw() {} 175 template <class U> 176 custom_allocator(const custom_allocator<U>&) throw() {} 177 }; 178 179- `native_type`' "type" (on a struct): In some cases, a more optimal C++ data 180 type exists for a given struct. For example, the following schema: 181 182 struct Vec2 { 183 x: float; 184 y: float; 185 } 186 187 generates the following Object-Based API class: 188 189 struct Vec2T : flatbuffers::NativeTable { 190 float x; 191 float y; 192 }; 193 194 However, it can be useful to instead use a user-defined C++ type since it 195 can provide more functionality, eg. 196 197 struct vector2 { 198 float x = 0, y = 0; 199 vector2 operator+(vector2 rhs) const { ... } 200 vector2 operator-(vector2 rhs) const { ... } 201 float length() const { ... } 202 // etc. 203 }; 204 205 The `native_type` attribute will replace the usage of the generated class 206 with the given type. So, continuing with the example, the generated 207 code would use |vector2| in place of |Vec2T| for all generated code. 208 209 However, becuase the native_type is unknown to flatbuffers, the user must 210 provide the following functions to aide in the serialization process: 211 212 namespace flatbuffers { 213 FlatbufferStruct Pack(const native_type& obj); 214 native_type UnPack(const FlatbufferStruct& obj); 215 } 216 217Finally, the following top-level attribute 218 219- `native_include`: "path" (at file level): Because the `native_type` attribute 220 can be used to introduce types that are unknown to flatbuffers, it may be 221 necessary to include "external" header files in the generated code. This 222 attribute can be used to directly add an #include directive to the top of 223 the generated code that includes the specified path directly. 224 225- `force_align`: this attribute may not be respected in the object API, 226 depending on the aligned of the allocator used with `new`. 227 228# External references. 229 230An additional feature of the object API is the ability to allow you to load 231multiple independent FlatBuffers, and have them refer to eachothers objects 232using hashes which are then represented as typed pointers in the object API. 233 234To make this work have a field in the objects you want to referred to which is 235using the string hashing feature (see `hash` attribute in the 236[schema](@ref flatbuffers_guide_writing_schema) documentation). Then you have 237a similar hash in the field referring to it, along with a `cpp_type` 238attribute specifying the C++ type this will refer to (this can be any C++ 239type, and will get a `*` added). 240 241Then, in JSON or however you create these buffers, make sure they use the 242same string (or hash). 243 244When you call `UnPack` (or `Create`), you'll need a function that maps from 245hash to the object (see `resolver_function_t` for details). 246 247# Using different pointer types. 248 249By default the object tree is built out of `std::unique_ptr`, but you can 250influence this either globally (using the `--cpp-ptr-type` argument to 251`flatc`) or per field (using the `cpp_ptr_type` attribute) to by any smart 252pointer type (`my_ptr<T>`), or by specifying `naked` as the type to get `T *` 253pointers. Unlike the smart pointers, naked pointers do not manage memory for 254you, so you'll have to manage their lifecycles manually. To reference the 255pointer type specified by the `--cpp-ptr-type` argument to `flatc` from a 256flatbuffer field set the `cpp_ptr_type` attribute to `default_ptr_type`. 257 258 259# Using different string type. 260 261By default the object tree is built out of `std::string`, but you can 262influence this either globally (using the `--cpp-str-type` argument to 263`flatc`) or per field using the `cpp_str_type` attribute. 264 265The type must support T::c_str() and T::length() as member functions. 266 267## Reflection (& Resizing) 268 269There is experimental support for reflection in FlatBuffers, allowing you to 270read and write data even if you don't know the exact format of a buffer, and 271even allows you to change sizes of strings and vectors in-place. 272 273The way this works is very elegant; there is actually a FlatBuffer schema that 274describes schemas (!) which you can find in `reflection/reflection.fbs`. 275The compiler, `flatc`, can write out any schemas it has just parsed as a binary 276FlatBuffer, corresponding to this meta-schema. 277 278Loading in one of these binary schemas at runtime allows you traverse any 279FlatBuffer data that corresponds to it without knowing the exact format. You 280can query what fields are present, and then read/write them after. 281 282For convenient field manipulation, you can include the header 283`flatbuffers/reflection.h` which includes both the generated code from the meta 284schema, as well as a lot of helper functions. 285 286And example of usage, for the time being, can be found in 287`test.cpp/ReflectionTest()`. 288 289## Mini Reflection 290 291A more limited form of reflection is available for direct inclusion in 292generated code, which doesn't any (binary) schema access at all. It was designed 293to keep the overhead of reflection as low as possible (on the order of 2-6 294bytes per field added to your executable), but doesn't contain all the 295information the (binary) schema contains. 296 297You add this information to your generated code by specifying `--reflect-types` 298(or instead `--reflect-names` if you also want field / enum names). 299 300You can now use this information, for example to print a FlatBuffer to text: 301 302 auto s = flatbuffers::FlatBufferToString(flatbuf, MonsterTypeTable()); 303 304`MonsterTypeTable()` is declared in the generated code for each type. The 305string produced is very similar to the JSON produced by the `Parser` based 306text generator. 307 308You'll need `flatbuffers/minireflect.h` for this functionality. In there is also 309a convenient visitor/iterator so you can write your own output / functionality 310based on the mini reflection tables without having to know the FlatBuffers or 311reflection encoding. 312 313## Storing maps / dictionaries in a FlatBuffer 314 315FlatBuffers doesn't support maps natively, but there is support to 316emulate their behavior with vectors and binary search, which means you 317can have fast lookups directly from a FlatBuffer without having to unpack 318your data into a `std::map` or similar. 319 320To use it: 321- Designate one of the fields in a table as they "key" field. You do this 322 by setting the `key` attribute on this field, e.g. 323 `name:string (key)`. 324 You may only have one key field, and it must be of string or scalar type. 325- Write out tables of this type as usual, collect their offsets in an 326 array or vector. 327- Instead of `CreateVector`, call `CreateVectorOfSortedTables`, 328 which will first sort all offsets such that the tables they refer to 329 are sorted by the key field, then serialize it. 330- Now when you're accessing the FlatBuffer, you can use `Vector::LookupByKey` 331 instead of just `Vector::Get` to access elements of the vector, e.g.: 332 `myvector->LookupByKey("Fred")`, which returns a pointer to the 333 corresponding table type, or `nullptr` if not found. 334 `LookupByKey` performs a binary search, so should have a similar speed to 335 `std::map`, though may be faster because of better caching. `LookupByKey` 336 only works if the vector has been sorted, it will likely not find elements 337 if it hasn't been sorted. 338 339## Direct memory access 340 341As you can see from the above examples, all elements in a buffer are 342accessed through generated accessors. This is because everything is 343stored in little endian format on all platforms (the accessor 344performs a swap operation on big endian machines), and also because 345the layout of things is generally not known to the user. 346 347For structs, layout is deterministic and guaranteed to be the same 348across platforms (scalars are aligned to their 349own size, and structs themselves to their largest member), and you 350are allowed to access this memory directly by using `sizeof()` and 351`memcpy` on the pointer to a struct, or even an array of structs. 352 353To compute offsets to sub-elements of a struct, make sure they 354are a structs themselves, as then you can use the pointers to 355figure out the offset without having to hardcode it. This is 356handy for use of arrays of structs with calls like `glVertexAttribPointer` 357in OpenGL or similar APIs. 358 359It is important to note is that structs are still little endian on all 360machines, so only use tricks like this if you can guarantee you're not 361shipping on a big endian machine (an `assert(FLATBUFFERS_LITTLEENDIAN)` 362would be wise). 363 364## Access of untrusted buffers 365 366The generated accessor functions access fields over offsets, which is 367very quick. These offsets are not verified at run-time, so a malformed 368buffer could cause a program to crash by accessing random memory. 369 370When you're processing large amounts of data from a source you know (e.g. 371your own generated data on disk), this is acceptable, but when reading 372data from the network that can potentially have been modified by an 373attacker, this is undesirable. 374 375For this reason, you can optionally use a buffer verifier before you 376access the data. This verifier will check all offsets, all sizes of 377fields, and null termination of strings to ensure that when a buffer 378is accessed, all reads will end up inside the buffer. 379 380Each root type will have a verification function generated for it, 381e.g. for `Monster`, you can call: 382 383~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} 384 bool ok = VerifyMonsterBuffer(Verifier(buf, len)); 385~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 386 387if `ok` is true, the buffer is safe to read. 388 389Besides untrusted data, this function may be useful to call in debug 390mode, as extra insurance against data being corrupted somewhere along 391the way. 392 393While verifying a buffer isn't "free", it is typically faster than 394a full traversal (since any scalar data is not actually touched), 395and since it may cause the buffer to be brought into cache before 396reading, the actual overhead may be even lower than expected. 397 398In specialized cases where a denial of service attack is possible, 399the verifier has two additional constructor arguments that allow 400you to limit the nesting depth and total amount of tables the 401verifier may encounter before declaring the buffer malformed. The default is 402`Verifier(buf, len, 64 /* max depth */, 1000000, /* max tables */)` which 403should be sufficient for most uses. 404 405## Text & schema parsing 406 407Using binary buffers with the generated header provides a super low 408overhead use of FlatBuffer data. There are, however, times when you want 409to use text formats, for example because it interacts better with source 410control, or you want to give your users easy access to data. 411 412Another reason might be that you already have a lot of data in JSON 413format, or a tool that generates JSON, and if you can write a schema for 414it, this will provide you an easy way to use that data directly. 415 416(see the schema documentation for some specifics on the JSON format 417accepted). 418 419There are two ways to use text formats: 420 421#### Using the compiler as a conversion tool 422 423This is the preferred path, as it doesn't require you to add any new 424code to your program, and is maximally efficient since you can ship with 425binary data. The disadvantage is that it is an extra step for your 426users/developers to perform, though you might be able to automate it. 427 428 flatc -b myschema.fbs mydata.json 429 430This will generate the binary file `mydata_wire.bin` which can be loaded 431as before. 432 433#### Making your program capable of loading text directly 434 435This gives you maximum flexibility. You could even opt to support both, 436i.e. check for both files, and regenerate the binary from text when 437required, otherwise just load the binary. 438 439This option is currently only available for C++, or Java through JNI. 440 441As mentioned in the section "Building" above, this technique requires 442you to link a few more files into your program, and you'll want to include 443`flatbuffers/idl.h`. 444 445Load text (either a schema or json) into an in-memory buffer (there is a 446convenient `LoadFile()` utility function in `flatbuffers/util.h` if you 447wish). Construct a parser: 448 449~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} 450 flatbuffers::Parser parser; 451~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 452 453Now you can parse any number of text files in sequence: 454 455~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} 456 parser.Parse(text_file.c_str()); 457~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 458 459This works similarly to how the command-line compiler works: a sequence 460of files parsed by the same `Parser` object allow later files to 461reference definitions in earlier files. Typically this means you first 462load a schema file (which populates `Parser` with definitions), followed 463by one or more JSON files. 464 465As optional argument to `Parse`, you may specify a null-terminated list of 466include paths. If not specified, any include statements try to resolve from 467the current directory. 468 469If there were any parsing errors, `Parse` will return `false`, and 470`Parser::err` contains a human readable error string with a line number 471etc, which you should present to the creator of that file. 472 473After each JSON file, the `Parser::fbb` member variable is the 474`FlatBufferBuilder` that contains the binary buffer version of that 475file, that you can access as described above. 476 477`samples/sample_text.cpp` is a code sample showing the above operations. 478 479## Threading 480 481Reading a FlatBuffer does not touch any memory outside the original buffer, 482and is entirely read-only (all const), so is safe to access from multiple 483threads even without synchronisation primitives. 484 485Creating a FlatBuffer is not thread safe. All state related to building 486a FlatBuffer is contained in a FlatBufferBuilder instance, and no memory 487outside of it is touched. To make this thread safe, either do not 488share instances of FlatBufferBuilder between threads (recommended), or 489manually wrap it in synchronisation primites. There's no automatic way to 490accomplish this, by design, as we feel multithreaded construction 491of a single buffer will be rare, and synchronisation overhead would be costly. 492 493## Advanced union features 494 495The C++ implementation currently supports vectors of unions (i.e. you can 496declare a field as `[T]` where `T` is a union type instead of a table type). It 497also supports structs and strings in unions, besides tables. 498 499For an example of these features, see `tests/union_vector`, and 500`UnionVectorTest` in `test.cpp`. 501 502Since these features haven't been ported to other languages yet, if you 503choose to use them, you won't be able to use these buffers in other languages 504(`flatc` will refuse to compile a schema that uses these features). 505 506These features reduce the amount of "table wrapping" that was previously 507needed to use unions. 508 509To use scalars, simply wrap them in a struct. 510 511## Depth limit of nested objects and stack-overflow control 512The parser of Flatbuffers schema or json-files is kind of recursive parser. 513To avoid stack-overflow problem the parser has a built-in limiter of 514recursion depth. Number of nested declarations in a schema or number of 515nested json-objects is limited. By default, this depth limit set to `64`. 516It is possible to override this limit with `FLATBUFFERS_MAX_PARSING_DEPTH` 517definition. This definition can be helpful for testing purposes or embedded 518applications. For details see [build](@ref flatbuffers_guide_building) of 519CMake-based projects. 520 521## Dependence from C-locale {#flatbuffers_locale_cpp} 522The Flatbuffers [grammar](@ref flatbuffers grammar) uses ASCII 523character set for identifiers, alphanumeric literals, reserved words. 524 525Internal implementation of the Flatbuffers depends from functions which 526depend from C-locale: `strtod()` or `strtof()`, for example. 527The library expects the dot `.` symbol as the separator of an integer 528part from the fractional part of a float number. 529Another separator symbols (`,` for example) will break the compatibility 530and may lead to an error while parsing a Flatbuffers schema or a json file. 531 532The Standard C locale is a global resource, there is only one locale for 533the entire application. Some modern compilers and platforms have 534locale-independent or locale-narrow functions `strtof_l`, `strtod_l`, 535`strtoll_l`, `strtoull_l` to resolve this dependency. 536These functions use specified locale rather than the global or per-thread 537locale instead. They are part of POSIX-2008 but not part of the C/C++ 538standard library, therefore, may be missing on some platforms. 539 540The Flatbuffers library try to detect these functions at configuration and 541compile time: 542- `_MSC_VER >= 1900`: check MSVC2012 or higher for MSVC buid 543- `_XOPEN_SOURCE>=700`: check POSIX-2008 for GCC/Clang build 544- `check_cxx_symbol_exists(strtof_l stdlib.h)`: CMake check of `strtod_f` 545 546After detection, the definition `FLATBUFFERS_LOCALE_INDEPENDENT` will be 547set to `0` or `1`. 548 549It is possible to test the compatibility of the Flatbuffers library with 550a specific locale using the environment variable `FLATBUFFERS_TEST_LOCALE`: 551```sh 552>FLATBUFFERS_TEST_LOCALE="" ./flattests 553>FLATBUFFERS_TEST_LOCALE="ru_RU.CP1251" ./flattests 554``` 555 556<br> 557