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) documentation. 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 GetMonster(flatbuffer)->UnPackTo(&monsterobj); 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 fbb.Finish(Monster::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 147Minimal Example: 148 149schema: 150 151```cpp 152 table mytable(native_custom_alloc:"custom_allocator") { 153 ... 154 } 155``` 156 157with `custom_allocator` defined before `flatbuffers.h` is included, as: 158 159```cpp 160 template <typename T> struct custom_allocator : public std::allocator<T> { 161 162 typedef T *pointer; 163 164 template <class U> 165 struct rebind { 166 typedef custom_allocator<U> other; 167 }; 168 169 pointer allocate(const std::size_t n) { 170 return std::allocator<T>::allocate(n); 171 } 172 173 void deallocate(T* ptr, std::size_t n) { 174 return std::allocator<T>::deallocate(ptr,n); 175 } 176 177 custom_allocator() throw() {} 178 179 template <class U> 180 custom_allocator(const custom_allocator<U>&) throw() {} 181 }; 182``` 183 184- `native_type("type")` (on a struct): In some cases, a more optimal C++ data 185type exists for a given struct. For example, the following schema: 186 187```cpp 188 struct Vec2 { 189 x: float; 190 y: float; 191 } 192``` 193 194generates the following Object-Based API class: 195 196```cpp 197 struct Vec2T : flatbuffers::NativeTable { 198 float x; 199 float y; 200 }; 201``` 202 203However, it can be useful to instead use a user-defined C++ type since it 204can provide more functionality, eg. 205 206```cpp 207 struct vector2 { 208 float x = 0, y = 0; 209 vector2 operator+(vector2 rhs) const { ... } 210 vector2 operator-(vector2 rhs) const { ... } 211 float length() const { ... } 212 // etc. 213 }; 214``` 215 216The `native_type` attribute will replace the usage of the generated class 217with the given type. So, continuing with the example, the generated 218code would use `vector2` in place of `Vec2T` for all generated code of 219the Object-Based API. 220 221However, because the `native_type` is unknown to flatbuffers, the user must 222provide the following functions to aide in the serialization process: 223 224```cpp 225 namespace flatbuffers { 226 Vec2 Pack(const vector2& obj); 227 vector2 UnPack(const Vec2& obj); 228 } 229``` 230 231- `native_type_pack_name("name")` (on a struct when `native_type` is 232 specified, too): when you want to use the same `native_type` multiple times 233 (e. g. with different precision) you must make the names of the Pack/UnPack 234 functions unique, otherwise you will run into compile errors. This attribute 235 appends a name to the expected Pack/UnPack functions. So when you 236 specify `native_type_pack_name("Vec2")` in the above example you now need to 237 implement these serialization functions instead: 238 239```cpp 240 namespace flatbuffers { 241 Vec2 PackVec2(const vector2& obj); 242 vector2 UnPackVec2(const Vec2& obj); 243 } 244``` 245 246Finally, the following top-level attributes: 247 248- `native_include("path")` (at file level): Because the `native_type` attribute 249 can be used to introduce types that are unknown to flatbuffers, it may be 250 necessary to include "external" header files in the generated code. This 251 attribute can be used to directly add an #include directive to the top of 252 the generated code that includes the specified path directly. 253 254- `force_align`: this attribute may not be respected in the object API, 255 depending on the aligned of the allocator used with `new`. 256 257# External references 258 259An additional feature of the object API is the ability to allow you to load 260multiple independent FlatBuffers, and have them refer to eachothers objects 261using hashes which are then represented as typed pointers in the object API. 262 263To make this work have a field in the objects you want to referred to which is 264using the string hashing feature (see `hash` attribute in the 265[schema](@ref flatbuffers_guide_writing_schema) documentation). Then you have 266a similar hash in the field referring to it, along with a `cpp_type` 267attribute specifying the C++ type this will refer to (this can be any C++ 268type, and will get a `*` added). 269 270Then, in JSON or however you create these buffers, make sure they use the 271same string (or hash). 272 273When you call `UnPack` (or `Create`), you'll need a function that maps from 274hash to the object (see `resolver_function_t` for details). 275 276# Using different pointer types 277 278By default the object tree is built out of `std::unique_ptr`, but you can 279influence this either globally (using the `--cpp-ptr-type` argument to 280`flatc`) or per field (using the `cpp_ptr_type` attribute) to by any smart 281pointer type (`my_ptr<T>`), or by specifying `naked` as the type to get `T *` 282pointers. Unlike the smart pointers, naked pointers do not manage memory for 283you, so you'll have to manage their lifecycles manually. To reference the 284pointer type specified by the `--cpp-ptr-type` argument to `flatc` from a 285flatbuffer field set the `cpp_ptr_type` attribute to `default_ptr_type`. 286 287# Using different string type 288 289By default the object tree is built out of `std::string`, but you can 290influence this either globally (using the `--cpp-str-type` argument to 291`flatc`) or per field using the `cpp_str_type` attribute. 292 293The type must support `T::c_str()`, `T::length()` and `T::empty()` as member functions. 294 295Further, the type must be constructible from std::string, as by default a 296std::string instance is constructed and then used to initialize the custom 297string type. This behavior impedes efficient and zero-copy construction of 298custom string types; the `--cpp-str-flex-ctor` argument to `flatc` or the 299per field attribute `cpp_str_flex_ctor` can be used to change this behavior, 300so that the custom string type is constructed by passing the pointer and 301length of the FlatBuffers String. The custom string class will require a 302constructor in the following format: `custom_str_class(const char *, size_t)`. 303Please note that the character array is not guaranteed to be NULL terminated, 304you should always use the provided size to determine end of string. 305 306## Reflection (& Resizing) 307 308There is experimental support for reflection in FlatBuffers, allowing you to 309read and write data even if you don't know the exact format of a buffer, and 310even allows you to change sizes of strings and vectors in-place. 311 312The way this works is very elegant; there is actually a FlatBuffer schema that 313describes schemas (\!) which you can find in `reflection/reflection.fbs`. 314The compiler, `flatc`, can write out any schemas it has just parsed as a binary 315FlatBuffer, corresponding to this meta-schema. 316 317Loading in one of these binary schemas at runtime allows you traverse any 318FlatBuffer data that corresponds to it without knowing the exact format. You 319can query what fields are present, and then read/write them after. 320 321For convenient field manipulation, you can include the header 322`flatbuffers/reflection.h` which includes both the generated code from the meta 323schema, as well as a lot of helper functions. 324 325And example of usage, for the time being, can be found in 326`test.cpp/ReflectionTest()`. 327 328## Mini Reflection 329 330A more limited form of reflection is available for direct inclusion in 331generated code, which doesn't do any (binary) schema access at all. It was designed 332to keep the overhead of reflection as low as possible (on the order of 2-6 333bytes per field added to your executable), but doesn't contain all the 334information the (binary) schema contains. 335 336You add this information to your generated code by specifying `--reflect-types` 337(or instead `--reflect-names` if you also want field / enum names). 338 339You can now use this information, for example to print a FlatBuffer to text: 340 341 auto s = flatbuffers::FlatBufferToString(flatbuf, MonsterTypeTable()); 342 343`MonsterTypeTable()` is declared in the generated code for each type. The 344string produced is very similar to the JSON produced by the `Parser` based 345text generator. 346 347You'll need `flatbuffers/minireflect.h` for this functionality. In there is also 348a convenient visitor/iterator so you can write your own output / functionality 349based on the mini reflection tables without having to know the FlatBuffers or 350reflection encoding. 351 352## Storing maps / dictionaries in a FlatBuffer 353 354FlatBuffers doesn't support maps natively, but there is support to 355emulate their behavior with vectors and binary search, which means you 356can have fast lookups directly from a FlatBuffer without having to unpack 357your data into a `std::map` or similar. 358 359To use it: 360- Designate one of the fields in a table as they "key" field. You do this 361 by setting the `key` attribute on this field, e.g. 362 `name:string (key)`. 363 You may only have one key field, and it must be of string or scalar type. 364- Write out tables of this type as usual, collect their offsets in an 365 array or vector. 366- Instead of `CreateVector`, call `CreateVectorOfSortedTables`, 367 which will first sort all offsets such that the tables they refer to 368 are sorted by the key field, then serialize it. 369- Now when you're accessing the FlatBuffer, you can use `Vector::LookupByKey` 370 instead of just `Vector::Get` to access elements of the vector, e.g.: 371 `myvector->LookupByKey("Fred")`, which returns a pointer to the 372 corresponding table type, or `nullptr` if not found. 373 `LookupByKey` performs a binary search, so should have a similar speed to 374 `std::map`, though may be faster because of better caching. `LookupByKey` 375 only works if the vector has been sorted, it will likely not find elements 376 if it hasn't been sorted. 377 378## Direct memory access 379 380As you can see from the above examples, all elements in a buffer are 381accessed through generated accessors. This is because everything is 382stored in little endian format on all platforms (the accessor 383performs a swap operation on big endian machines), and also because 384the layout of things is generally not known to the user. 385 386For structs, layout is deterministic and guaranteed to be the same 387across platforms (scalars are aligned to their 388own size, and structs themselves to their largest member), and you 389are allowed to access this memory directly by using `sizeof()` and 390`memcpy` on the pointer to a struct, or even an array of structs. 391 392To compute offsets to sub-elements of a struct, make sure they 393are a structs themselves, as then you can use the pointers to 394figure out the offset without having to hardcode it. This is 395handy for use of arrays of structs with calls like `glVertexAttribPointer` 396in OpenGL or similar APIs. 397 398It is important to note is that structs are still little endian on all 399machines, so only use tricks like this if you can guarantee you're not 400shipping on a big endian machine (an `assert(FLATBUFFERS_LITTLEENDIAN)` 401would be wise). 402 403## Access of untrusted buffers 404 405The generated accessor functions access fields over offsets, which is 406very quick. These offsets are not verified at run-time, so a malformed 407buffer could cause a program to crash by accessing random memory. 408 409When you're processing large amounts of data from a source you know (e.g. 410your own generated data on disk), this is acceptable, but when reading 411data from the network that can potentially have been modified by an 412attacker, this is undesirable. 413 414For this reason, you can optionally use a buffer verifier before you 415access the data. This verifier will check all offsets, all sizes of 416fields, and null termination of strings to ensure that when a buffer 417is accessed, all reads will end up inside the buffer. 418 419Each root type will have a verification function generated for it, 420e.g. for `Monster`, you can call: 421 422```cpp 423 bool ok = VerifyMonsterBuffer(Verifier(buf, len)); 424``` 425 426if `ok` is true, the buffer is safe to read. 427 428Besides untrusted data, this function may be useful to call in debug 429mode, as extra insurance against data being corrupted somewhere along 430the way. 431 432While verifying a buffer isn't "free", it is typically faster than 433a full traversal (since any scalar data is not actually touched), 434and since it may cause the buffer to be brought into cache before 435reading, the actual overhead may be even lower than expected. 436 437In specialized cases where a denial of service attack is possible, 438the verifier has two additional constructor arguments that allow 439you to limit the nesting depth and total amount of tables the 440verifier may encounter before declaring the buffer malformed. The default is 441`Verifier(buf, len, 64 /* max depth */, 1000000, /* max tables */)` which 442should be sufficient for most uses. 443 444## Text & schema parsing 445 446Using binary buffers with the generated header provides a super low 447overhead use of FlatBuffer data. There are, however, times when you want 448to use text formats, for example because it interacts better with source 449control, or you want to give your users easy access to data. 450 451Another reason might be that you already have a lot of data in JSON 452format, or a tool that generates JSON, and if you can write a schema for 453it, this will provide you an easy way to use that data directly. 454 455(see the schema documentation for some specifics on the JSON format 456accepted). 457 458Schema evolution compatibility for the JSON format follows the same rules as the binary format (JSON formatted data will be forwards/backwards compatible with schemas that evolve in a compatible way). 459 460There are two ways to use text formats: 461 462#### Using the compiler as a conversion tool 463 464This is the preferred path, as it doesn't require you to add any new 465code to your program, and is maximally efficient since you can ship with 466binary data. The disadvantage is that it is an extra step for your 467users/developers to perform, though you might be able to automate it. 468 469 flatc -b myschema.fbs mydata.json 470 471This will generate the binary file `mydata_wire.bin` which can be loaded 472as before. 473 474#### Making your program capable of loading text directly 475 476This gives you maximum flexibility. You could even opt to support both, 477i.e. check for both files, and regenerate the binary from text when 478required, otherwise just load the binary. 479 480This option is currently only available for C++, or Java through JNI. 481 482As mentioned in the section "Building" above, this technique requires 483you to link a few more files into your program, and you'll want to include 484`flatbuffers/idl.h`. 485 486Load text (either a schema or json) into an in-memory buffer (there is a 487convenient `LoadFile()` utility function in `flatbuffers/util.h` if you 488wish). Construct a parser: 489 490```cpp 491 flatbuffers::Parser parser; 492``` 493 494Now you can parse any number of text files in sequence: 495 496```cpp 497 parser.Parse(text_file.c_str()); 498``` 499 500This works similarly to how the command-line compiler works: a sequence 501of files parsed by the same `Parser` object allow later files to 502reference definitions in earlier files. Typically this means you first 503load a schema file (which populates `Parser` with definitions), followed 504by one or more JSON files. 505 506As optional argument to `Parse`, you may specify a null-terminated list of 507include paths. If not specified, any include statements try to resolve from 508the current directory. 509 510If there were any parsing errors, `Parse` will return `false`, and 511`Parser::error_` contains a human readable error string with a line number 512etc, which you should present to the creator of that file. 513 514After each JSON file, the `Parser::fbb` member variable is the 515`FlatBufferBuilder` that contains the binary buffer version of that 516file, that you can access as described above. 517 518`samples/sample_text.cpp` is a code sample showing the above operations. 519 520## Threading 521 522Reading a FlatBuffer does not touch any memory outside the original buffer, 523and is entirely read-only (all const), so is safe to access from multiple 524threads even without synchronisation primitives. 525 526Creating a FlatBuffer is not thread safe. All state related to building 527a FlatBuffer is contained in a FlatBufferBuilder instance, and no memory 528outside of it is touched. To make this thread safe, either do not 529share instances of FlatBufferBuilder between threads (recommended), or 530manually wrap it in synchronisation primitives. There's no automatic way to 531accomplish this, by design, as we feel multithreaded construction 532of a single buffer will be rare, and synchronisation overhead would be costly. 533 534## Advanced union features 535 536The C++ implementation currently supports vectors of unions (i.e. you can 537declare a field as `[T]` where `T` is a union type instead of a table type). It 538also supports structs and strings in unions, besides tables. 539 540For an example of these features, see `tests/union_vector`, and 541`UnionVectorTest` in `test.cpp`. 542 543Since these features haven't been ported to other languages yet, if you 544choose to use them, you won't be able to use these buffers in other languages 545(`flatc` will refuse to compile a schema that uses these features). 546 547These features reduce the amount of "table wrapping" that was previously 548needed to use unions. 549 550To use scalars, simply wrap them in a struct. 551 552## Depth limit of nested objects and stack-overflow control 553The parser of Flatbuffers schema or json-files is kind of recursive parser. 554To avoid stack-overflow problem the parser has a built-in limiter of 555recursion depth. Number of nested declarations in a schema or number of 556nested json-objects is limited. By default, this depth limit set to `64`. 557It is possible to override this limit with `FLATBUFFERS_MAX_PARSING_DEPTH` 558definition. This definition can be helpful for testing purposes or embedded 559applications. For details see [build](@ref flatbuffers_guide_building) of 560CMake-based projects. 561 562## Dependence from C-locale {#flatbuffers_locale_cpp} 563The Flatbuffers [grammar](@ref flatbuffers grammar) uses ASCII 564character set for identifiers, alphanumeric literals, reserved words. 565 566Internal implementation of the Flatbuffers depends from functions which 567depend from C-locale: `strtod()` or `strtof()`, for example. 568The library expects the dot `.` symbol as the separator of an integer 569part from the fractional part of a float number. 570Another separator symbols (`,` for example) will break the compatibility 571and may lead to an error while parsing a Flatbuffers schema or a json file. 572 573The Standard C locale is a global resource, there is only one locale for 574the entire application. Some modern compilers and platforms have 575locale-independent or locale-narrow functions `strtof_l`, `strtod_l`, 576`strtoll_l`, `strtoull_l` to resolve this dependency. 577These functions use specified locale rather than the global or per-thread 578locale instead. They are part of POSIX-2008 but not part of the C/C++ 579standard library, therefore, may be missing on some platforms. 580The Flatbuffers library try to detect these functions at configuration and 581compile time: 582- CMake `"CMakeLists.txt"`: 583 - Check existence of `strtol_l` and `strtod_l` in the `<stdlib.h>`. 584- Compile-time `"/include/base.h"`: 585 - `_MSC_VER >= 1900`: MSVC2012 or higher if build with MSVC. 586 - `_XOPEN_SOURCE>=700`: POSIX-2008 if build with GCC/Clang. 587 588After detection, the definition `FLATBUFFERS_LOCALE_INDEPENDENT` will be 589set to `0` or `1`. 590To override or stop this detection use CMake `-DFLATBUFFERS_LOCALE_INDEPENDENT={0|1}` 591or predefine `FLATBUFFERS_LOCALE_INDEPENDENT` symbol. 592 593To test the compatibility of the Flatbuffers library with 594a specific locale use the environment variable `FLATBUFFERS_TEST_LOCALE`: 595```sh 596>FLATBUFFERS_TEST_LOCALE="" ./flattests 597>FLATBUFFERS_TEST_LOCALE="ru_RU.CP1251" ./flattests 598``` 599 600## Support of floating-point numbers 601The Flatbuffers library assumes that a C++ compiler and a CPU are 602compatible with the `IEEE-754` floating-point standard. 603The schema and json parser may fail if `fast-math` or `/fp:fast` mode is active. 604 605### Support of hexadecimal and special floating-point numbers 606According to the [grammar](@ref flatbuffers_grammar) `fbs` and `json` files 607may use hexadecimal and special (`NaN`, `Inf`) floating-point literals. 608The Flatbuffers uses `strtof` and `strtod` functions to parse floating-point 609literals. The Flatbuffers library has a code to detect a compiler compatibility 610with the literals. If necessary conditions are met the preprocessor constant 611`FLATBUFFERS_HAS_NEW_STRTOD` will be set to `1`. 612The support of floating-point literals will be limited at compile time 613if `FLATBUFFERS_HAS_NEW_STRTOD` constant is less than `1`. 614In this case, schemas with hexadecimal or special literals cannot be used. 615 616### Comparison of floating-point NaN values 617The floating-point `NaN` (`not a number`) is special value which 618representing an undefined or unrepresentable value. 619`NaN` may be explicitly assigned to variables, typically as a representation 620for missing values or may be a result of a mathematical operation. 621The `IEEE-754` defines two kind of `NaNs`: 622- Quiet NaNs, or `qNaNs`. 623- Signaling NaNs, or `sNaNs`. 624 625According to the `IEEE-754`, a comparison with `NaN` always returns 626an unordered result even when compared with itself. As a result, a whole 627Flatbuffers object will be not equal to itself if has one or more `NaN`. 628Flatbuffers scalar fields that have the default value are not actually stored 629in the serialized data but are generated in code (see [Writing a schema](@ref flatbuffers_guide_writing_schema)). 630Scalar fields with `NaN` defaults break this behavior. 631If a schema has a lot of `NaN` defaults the Flatbuffers can override 632the unordered comparison by the ordered: `(NaN==NaN)->true`. 633This ordered comparison is enabled when compiling a program with the symbol 634`FLATBUFFERS_NAN_DEFAULTS` defined. 635Additional computations added by `FLATBUFFERS_NAN_DEFAULTS` are very cheap 636if GCC or Clang used. These compilers have a compile-time implementation 637of `isnan` checking which MSVC does not. 638 639<br> 640