1# EASTL Best Practices 2 3In this document we discuss best practices for using EASTL. The primary emphasis is on performance with a secondary emphasis on correctness and maintainability. Some best practices apply only to some situations, and these will be pointed out as we go along. In order to be easily digestible, we present these practices as a list of items in the tone of the Effective C++ series of books. 4 5## Summary 6 7The descriptions here are intentionally terse; this is to make them easier to visually scan. 8 91. [Consider intrusive containers.](#consider-intrusive-containers) 102. [Consider fixed-size containers.](#consider-fixed-size-containers) 113. [Consider custom allocators.](#consider-custom-allocators) 124. [Consider hash tables instead of maps.](#consider-hash-tables-instead-of-maps) 135. [Consider a vector_map (a.k.a. sorted vector) for unchanging data.](#consider-a-vector_map-aka-sorted-vector-for-unchanging-data) 146. [Consider slist instead of list.](#consider-slist-instead-of-list) 157. [Avoid redundant end() and size() in loops.](#avoid-redundant-end-and-size-in-loops) 168. [Iterate containers instead of using operator\[\].](#iterate-containers-instead-of-using-operator) 179. [Learn to use the string class appropriately.](#learn-to-use-the-string-class-appropriately) 1810. [Cache list size if you want size() to be O(1).](#cache-list-size-if-you-want-listsize-to-be-o1) 1911. [Use empty() instead of size() when possible.](#use-empty-instead-of-size-when-possible) 2012. [Know your container efficiencies.](#know-your-container-efficiencies) 2113. [Use vector::reserve.](#use-vectorreserve) 2214. [Use vector::set_capacity to trim memory usage.](#use-vectorset_capacity-to-trim-memory-usage) 2315. [Use swap() instead of a manually implemented version.](#use-swap-instead-of-a-manually-implemented-version) 2416. [Consider storing pointers instead of objects.](#consider-storing-pointers-instead-of-objects) 2517. [Consider smart pointers instead of raw pointers.](#consider-smart-pointers-instead-of-raw-pointers) 2618. [Use iterator pre-increment instead of post-increment.](#use-iterator-pre-increment-instead-of-post-increment) 2719. [Make temporary references so the code can be traced/debugged.](#make-temporary-references-so-the-code-can-be-traceddebugged) 2820. [Consider bitvector or bitset instead of vector\<bool>.](#consider-bitvector-or-bitset-instead-of-vector) 2921. [Vectors can be treated as contiguous memory.](#vectors-can-be-treated-as-contiguous-memory) 3022. [Search hash_map\<string> via find_as() instead of find().](#search-hash_map-via-find_as-instead-of-find) 3123. [Take advantage of type_traits (e.g. EASTL_DECLARE_TRIVIAL_RELOCATE).](#take-advantage-of-type_traits-eg-eastl_declare_trivial_relocate) 3224. [Name containers to track memory usage.](#name-containers-to-track-memory-usage) 3325. [Learn the algorithms.](#learn-the-algorithms) 3426. [Pass and return containers by reference instead of value.](#pass-and-return-containers-by-reference-instead-of-value) 3527. [Consider using reset() for fast container teardown.](#consider-using-reset-for-fast-container-teardown) 3628. [Consider using fixed_substring instead of copying strings.](#consider-using-fixed_substring-instead-of-copying-strings) 3729. [Consider using vector::push_back(void).](#consider-using-vectorpush_backvoid) 38 39## Detail 40 41### Consider intrusive containers. 42 43Intrusive containers (such as intrusive_list) differ from regular containers (such as list) in that they use the stored objects to manage the linked list instead of using nodes allocated from a memory heap. The result is better usage of memory. Additionally intrusive_list objects can be removed from their list without knowing what list they belong to. To make an intrusive_list of Widgets, you have Widget inherit from intrusive_list_node or simply have mpPrev/mpNext member variables. 44 45To create an intrusive_list container, you can use the following code: 46 47```cpp 48class Widget : public intrusive_list_node 49 50{ }; 51 52 53 54intrusive_list<Widget> widgetList; 55 56widgetList.push_back(someWidget); 57``` 58 59### Consider fixed-size containers. 60 61Fixed-size containers (such as fixed_list) are variations of regular containers (such as list) in that they allocate from a fixed block of local memory instead of allocating from a generic heap. The result is better usage of memory due to reduced fragmentation, better cache behavior, and faster allocation/deallocation. The presence of fixed-size containers negate the most common complaint that people have about STL: that it fragments the heap or "allocates all over the place." 62 63EASTL fixed containers include: 64 65* fixed_list 66* fixed_slist 67* fixed_vector 68* fixed_string 69* fixed_map 70* fixed_multimap 71* fixed_set 72* fixed_multiset 73* fixed_hash_map 74* fixed_hash_multimap 75* fixed_hash_set 76* fixed_hash_multiset 77 78To create a fixed_set, you can use the following code: 79 80```cpp 81fixed_set<int, 25> intSet; // Create a set capable of holding 250 elements. 82 83intSet.push_back(37); 84``` 85 86### Consider custom allocators. 87 88While EASTL provides fixed-size containers in order to control container memory usage, EASTL lets you assign a custom allocator to any container. This lets you define your own memory pool. EASTL has a more flexible and powerful mechanism of doing this that standard STL, as EASTL understands object alignment requirements, allows for debug naming, allows for sharing allocators across containers, and allows dynamic allocator assignment. 89 90To create a list container that uses your custom allocator and uses block naming, you can use the following code: 91 92```cpp 93list<int> intList(pSomeAllocator, "graphics/intList"); 94 95intList.push_back(37); 96``` 97 98### Consider hash tables instead of maps. 99 100Hash containers (such as hash_map) provide the same interface as associative containers (such as map) but have faster lookup and use less memory. The primary disadvantage relative to associative containers is that hash containers are not sorted. 101 102To make a hash_map (dictionary) of integers to strings, you can use the following code: 103```cpp 104hash_map<int, const char*> stringTable; 105 106stringTable[37] = "hello"; 107``` 108 109### Consider a vector_map (a.k.a. sorted vector) for unchanging data. 110 111You can improve speed, memory usage, and cache behavior by using a vector_map instead of a map (or vector_set instead of set, etc.). The primary disadvantage of vector_map is that insertions and removal of elements is O(n) instead of O(1). However, if your associative container is not going to be changing much or at all, you can benefit from using a vector_map. Consider calling reserve on the vector_map in order to set the desired capacity up front. 112 113To make a vector_set, you can use the following code: 114 115```cpp 116vector_set<int> intSet(16); // Create a vector_set with an initial capacity of 16. 117 118intSet.insert(37); 119``` 120 121Note that you can use containers other than vector to implement vector_set. Here's how you do it with deque: 122 123```cpp 124vector_set<int, less<int>, EASTLAllocatorType, deque<int> > intSet; 125 126intSet.insert(37); 127``` 128 129### Consider slist instead of list. 130 131An slist is a singly-linked list; it is much like a list except that it can only be traversed in a forward direction and not a backward direction. The benefit is that each node is 4 bytes instead of 8 bytes. This is a small improvement, but if you don't need reverse iteration then it can be an improvement. There's also intrusive_slist as an option. 132 133To make an slist, you can use the following code: 134 135```cpp 136slist<int> intSlist; 137 138intSlist.push_front(37); 139``` 140 141### Avoid redundant end() and size() in loops. 142 143Instead of writing code like this: 144 145```cpp 146for(deque<int>::iterator it = d.begin(); it != d.end(); ++it) 147 148 ... 149``` 150 151write code like this: 152 153```cpp 154for(deque<int>::iterator it = d.begin(), itEnd = d.end(); it != itEnd; ++it) 155 156 ... 157``` 158 159The latter avoids a function call and return of an object (which in deque's case happens to be more than just a pointer). The above only works when the container is unchanged or for containers that have a constant end value. But "constant end value" we mean containers which can be modified but end always remains the same. 160 161| Constant begin | Non-constant begin | Constant end | Non-constant end | 162|------|------|------|------| 163| array<sup>1</sup> | string<br> vector<br> deque<br> intrusive_list<br> intrusive_slist<br> vector_map<br> vector_multimap<br> vector_set<br> vector_multiset<br> bit_vector<br> hash_map<br> hash_multimap<br> hash_set<br> hash_multiset<br> intrusive_hash_map<br> intrusive_hash_multimap<br> intrusive_hash_set<br> intrusive_hash_multiset | array<br> list<br> slist<br> intrusive_list<br> intrusive_slist<br> map<br> multimap<br> set<br> multiset<br> hash_map<sup>2</sup><br> hash_multimap<sup>2</sup><br> hash_set<sup>2</sup><br> hash_multiset<sup>2</sup><br> intrusive_hash_map<br> intrusive_hash_multimap<br> intrusive_hash_set<br> intrusive_hash_multiset | string<br> vector<br> deque<br> vector_map<br> vector_multimap<br> vector_set<br> vector_multiset<br> bit_vector | 164 165* <sup>1</sup> Arrays can be neither resized nor reallocated. 166* <sup>2</sup> Constant end if the hashtable can't/won't re-hash. Non-constant if it can re-hash. 167 168### Iterate containers instead of using operator[]. 169 170It's faster to iterate random access containers via iterators than via operator[], though operator[] usage may look simpler. 171 172Instead of doing this: 173 174```cpp 175for(unsigned i = 0, iEnd = intVector.size(); i != iEnd; ++i) 176 177 intVector[i] = 37; 178``` 179 180you can execute more efficiently by doing this: 181 182```cpp 183for(vector<int>::iterator it = intVector.begin(), itEnd = intVector.end(); it != itEnd; ++it) 184 185 *it = 37; 186``` 187 188### Learn to use the string class appropriately. 189 190Oddly enough, the most mis-used STL container is easily the string class. The tales of string abuse could rival the 1001 Arabian Nights. Most of the abuses involve doing things in a harder way than need be. In examining the historical mis-uses of string, it is clear that many of the problems stem from the user thinking in terms of C-style string operations instead of object-oriented strings. This explains why statements such as strlen(s.c_str()) are so common, whereas the user could just use s.length() instead and be both clearer and more efficient. 191 192Here we provide a table of actual collected examples of things done and how they could have been done instead. 193 194| What was written | What could have been written | 195|------|------| 196| `s = s.Left(i) + '+' + s.Right(s.length() - i - 1);` | `s[i] = '+';` | 197| `string s(""); // This is the most commonly found misuse.` | `string s;` | 198| `s = "";` | `s.clear();` | 199| `s.c_str()[0] = 'u';` | `s[0] = 'u';` | 200| `len = strlen(s.c_str());` | `len = s.length();` | 201| `s = string("u");` | `s = "u";` | 202| `puts(s + string("u"));` | `puts(s + "u");` | 203| `string s(" ");`<br> `puts(s.c_str());` | `puts(" ");` | 204| `s.sprintf("u");` | s = "u";` | 205| `char array[32];`<br> `sprintf(array, "%d", 10);`<br> `s = string(array);` | `s.sprintf("%d", 10);` | 206 207The chances are that if you want to do something with a string, there is a very basic way to do it. You don't want your code to appear in a future version of the above table. 208 209### Cache list size if you want list::size() to be O(1). 210 211EASTL's list, slist, intrusive_list, and intrusive_slist containers have a size() implementation which is O(n). That is, these containers don't keep a count (cache) of the current list size and when you call the size() function they iterate the list. This is by design and the reasoning behind it has been deeply debated and considered (and is discussed in the FAQ and the list header file). In summary, list doesn't cache its size because the only function that would benefit is the size function while many others would be negatively impacted and the memory footprint would be negatively impacted, yet list::size is not a very frequently called function in well-designed code. At the same time, nothing prevents the user from caching the size himself, though admittedly it adds some tedium and risk to the code writing process. 212 213Here's an example of caching the list size manually: 214 215```cpp 216list<int> intList; 217 218 size_t n = 0; 219 220 221 222 intList.push_back(37); 223 224 ++n; 225 226 intList.pop_front(); 227 228 --n; 229``` 230 231### Use empty() instead of size() when possible. 232 233All conventional containers have both an empty function and a size function. For all containers empty() executes with O(1) (constant time) efficiency. However, this is not so for size(), as some containers need to calculate the size and others need to do pointer subtraction (which may involve integer division) to find the size. 234 235### Know your container efficiencies. 236 237The above two practices lead us to this practice, which is a generalization of the above. We present a table of basic information for the conventional EASTL containers. The values are described at the bottom. 238 239| Container | empty() efficiency | size() efficiency | operator[] efficiency | insert() efficiency | erase() efficiency | find() efficiency | sort efficiency | 240|------|------|------|------|------|------|------|------| 241| slist | 1 | O(n) | - | O(1) | O(1) | O(n) | O(n+) | 242| list | 1 | n | - | 1 | 1 | n | n log(n) | 243| intrusive_slist | 1 | n | - | 1 | 1 | 1 | n+ | 244| intrusive_list | 1 | n | - | 1 | 1 | 1 | n log(n) | 245| array | 1 | 1 | 1 | - | - | n | n log(n) | 246| vector | 1 | 1<sup>a</sup> | 1 | 1 at end, else n | 1 at end, else n | n | n log(n) | 247| vector_set | 1 | 1<sup>a</sup> | 1 | 1 at end, else n | 1 at end, else n | log(n) | 1 | 248| vector_multiset | 1 | 1<sup>a</sup> | 1 | 1 at end, else n | 1 at end, else n | log(n) | 1 | 249| vector_map | 1 | 1<sup>a</sup> | 1 | 1 at end, else n | 1 at end, else n | log(n) | 1 | 250| vector_multimap | 1 | 1<sup>a</sup> | 1 | 1 at end, else n | 1 at end, else n | log(n) | 1 | 251| deque | 1 | 1<sup>a</sup> | 1 | 1 at begin or end, else n / 2 | 1 at begin or end, else n / 2 | n | n log(n) | 252| bit_vector | 1 | 1<sup>a</sup> | 1 | 1 at end, else n | 1 at end, else n | n | n log(n) | 253| string, cow_string | 1 | 1<sup>a</sup> | 1 | 1 at end, else n | 1 at end, else n | n | n log(n) | 254| set | 1 | 1 | - | log(n) | log(n) | log(n) | 1 | 255| multiset | 1 | 1 | - | log(n) | log(n) | log(n) | 1 | 256| map | 1 | 1 | log(n) | log(n) | log(n) | log(n) | 1 | 257| multimap | 1 | 1 | - | log(n) | log(n) | log(n) | 1 | 258| hash_set | 1 | 1 | - | 1 | 1 | 1 | - | 259| hash_multiset | 1 | 1 | - | 1 | 1 | 1 | - | 260| hash_map | 1 | 1 | - | 1 | 1 | 1 | - | 261| hash_multimap | 1 | 1 | - | 1 | 1 | 1 | - | 262| intrusive_hash_set | 1 | 1 | - | 1 | 1 | 1 | - | 263| intrusive_hash_multiset | 1 | 1 | - | 1 | 1 | 1 | - | 264| intrusive_hash_map | 1 | 1 | - | 1 | 1 | 1 | - | 265| intrusive_hash_multimap | 1 | 1 | - | 1 | 1 | 1 | - | 266 267Notes: 268 269* \- means that the operation does not exist. 270* 1 means amortized constant time. Also known as O(1) 271* n means time proportional to the container size. Also known as O(n) 272* log(n) means time proportional to the natural logarithm of the container size. Also known as O(log(n)) 273* n log(n) means time proportional to log(n) times the size of the container. Also known as O(n log(n)) 274* n+ means that the time is at least n, and possibly higher. 275* Inserting at the end of a vector may cause the vector to be resized; resizing a vector is O(n). However, the amortized time complexity for vector insertions at the end is constant. 276* Sort assumes the usage of the best possible sort for a large container of random data. Some sort algorithms (e.g. quick_sort) require random access iterators and so the sorting of some containers requires a different sort algorithm. We do not include bucket or radix sorts, as they are always O(n). 277* <sup>a</sup> vector, deque, string size is O(1) but involves pointer subtraction and thus integer division and so is not as efficient as containers that store the size directly. 278 279### Use vector::reserve. 280 281You can prevent vectors (and strings) from reallocating as you add items by specifying up front how many items you will be requiring. You can do this in the constructor or by calling the reserve function at any time. The capacity function returns the amount of space which is currently reserved. 282 283Here's how you could specify reserved capacity in a vector: 284 285```cpp 286vector<Widget> v(37); // Reserve space to hold up to 37 items. 287 288 or 289 290vector<Widget> v; // This empty construction causes to memory to be allocated or reserved. 291 292 v.reserve(37); 293``` 294 295The EASTL vector (and string) implementation looks like this: 296 297```cpp 298template <typename T> 299 300 class vector { 301 302 T* mpBegin; // Beginning of used element memory. 303 304 T* mpEnd; // End of used element memory. 305 306 T* mpCapacity; // End of storage capacity. Is >= mpEnd 307 308 } 309``` 310 311Another approach to being efficient with vector memory usage is to use fixed_vector. 312 313### Use vector::set_capacity to trim memory usage. 314 315A commonly asked question about vectors and strings is, "How do I reduce the capacity of a vector?" The conventional solution for std STL is to use the somewhat non-obvious trick of using vector<Widget>(v).swap(v). EASTL provides the same functionality via a member function called set_capacity() which is present in both the vector and string classes. 316 317An example of reducing a vector is the following: 318 319```cpp 320vector<Widget> v; 321 322... 323 324 v.set_capacity(); 325``` 326 327An example of resizing to zero and completely freeing the memory of a vector is the following: 328 329```cpp 330vector<Widget> v; 331 332 ... 333 334 v.set_capacity(0); 335``` 336 337### Use swap() instead of a manually implemented version. 338 339The generic swap algorithm provides a basic version for any kind of object. However, each EASTL container provides a specialization of swap which is optimized for that container. For example, the list container implements swap by simply swapping the internal member pointers and not by moving individual elements. 340 341### Consider storing pointers instead of objects. 342 343There are times when storing pointers to objects is more efficient or useful than storing objects directly in containers. It can be more efficient to store pointers when the objects are big and the container may need to construct, copy, and destruct objects during sorting or resizing. Moving pointers is usually faster than moving objects. It can be useful to store pointers instead of objects when somebody else owns the objects or the objects are in another container. It might be useful for a Widget to be in a list and in a hash table at the same time. 344 345### Consider smart pointers instead of raw pointers. 346 347If you take the above recommendation and store objects as pointers instead of as objects, you may want to consider storing them as smart pointers instead of as regular pointers. This is particularly useful for when you want to delete the object when it is removed from the container. Smart pointers will automatically delete the pointed-to object when the smart pointer is destroyed. Otherwise, you will have to be careful about how you work with the list so that you don't generate memory leaks. Smart pointers implement a shared reference count on the stored pointer, as so any operation you do on a smart pointer container will do the right thing. Any pointer can be stored in a smart pointer, and custom new/delete mechanisms can work with smart pointers. The primary smart pointer is shared_ptr. 348 349Here is an example of creating and using a shared_ptr: 350 351```cpp 352typedef shared_ptr<Widget> WPtr; 353 354 list<WPtr> wList; 355 356 357 358 wList.push_back(WPtr(new Widget)); // The user may have operator new/delete overrides. 359 360wList.pop_back(); // Implicitly deletes the Widget. 361``` 362 363Here is an example of creating and using a shared_ptr that uses a custom allocation and deallocation mechanism: 364 365```cpp 366typedef shared_ptr<Widget, EASTLAllocatorType, WidgetDelete> WPtr; // WidgetDelete is a custom destroyer. 367 368 list<WPtr> wList; 369 370 371 372 wList.push_back(WPtr(WidgetCreate(Widget))); // WidgetCreate is a custom allocator. 373 374wList.pop_back(); // Implicitly calls WidgetDelete. 375``` 376 377### Use iterator pre-increment instead of post-increment. 378 379Pre-increment (e.g. ++x) of iterators is better than post-increment (x++) when the latter is not specifically needed. It is common to find code that uses post-incrementing when it could instead use pre-incrementing; presumably this is due to post-increment looking a little better visually. The problem is that the latter constructs a temporary object before doing the increment. With built-in types such as pointers and integers, the compiler will recognize that the object is a trivial built-in type and that the temporary is not needed, but the compiler cannot do this for other types, even if the compiler sees that the temporary is not used; this is because the constructor may have important side effects and the compiler would be broken if it didn't construct the temporary object. 380 381EASTL iterators are usually not trivial types and so it's best not to hope the compiler will do the best thing. Thus you should always play it safe an use pre-increment of iterators whenever post-increment is not required. 382 383Here is an example of using iterator pre-increment; for loops like this should always use pre-increment: 384 385```cpp 386for(set<int>::iterator it(intSet.begin()), itEnd(intSet.end()); it != itEnd; ++it) 387 388 *it = 37; 389``` 390 391### Make temporary references so the code can be traced/debugged. 392 393Users want to be able to inspect or modify variables which are referenced by iterators. While EASTL containers and iterators are designed to make this easier than other STL implementations, it makes things very easy if the code explicitly declares a reference to the iterated element. In addition to making the variable easier to debug, it also makes code easier to read and makes the debug (and possibly release) version of the application run more efficiently. 394 395Instead of doing this: 396 397```cpp 398for(list<Widget>::iterator it = wl.begin(), itEnd = wl.end(); it != itEnd; ++it) { 399 400 (*it).x = 37; 401 402 (*it).y = 38; 403 404 (*it).z = 39; 405 406 } 407``` 408 409Consider doing this: 410 411```cpp 412for(list<Widget>::iterator it = wl.begin(), itEnd = wl.end(); it != itEnd; ++it) { 413 414 Widget& w = *it; // The user can easily inspect or modify w here. 415 416 w.x = 37; 417 418 w.y = 38; 419 420 w.z = 39; 421 422 } 423``` 424 425### Consider bitvector or bitset instead of vector<bool>. 426 427In EASTL, a vector of bool is exactly that. It intentionally does not attempt to make a specialization which implements a packed bit array. The bitvector class is specifically designed for this purpose. There are arguments either way, but if vector<bool> were allowed to be something other than an array of bool, it would go against user expectations and prevent users from making a true array of bool. There's a mechanism for specifically getting the bit packing, and it is bitvector. 428 429Additionally there is bitset, which is not a conventional iterateable container but instead acts like bit flags. bitset may better suit your needs than bitvector if you need to do flag/bit operations instead of array operations. bitset does have an operator[], though. 430 431### Vectors can be treated as contiguous memory. 432 433EASTL vectors (and strings) guarantee that elements are present in a linear contiguous array. This means that you can use a vector as you would a C-style array by using the vector data() member function or by using &v[0]. 434 435To use a vector as a pointer to an array, you can use the following code: 436 437```cpp 438struct Widget { 439 440 uint32_t x; 441 442 uint32_t y; 443 444 }; 445 446 447 448 vector<Widget> v; 449 450 451 452 quick_sort((uint64_t*)v.data(), (uint64_t*)(v.data() + v.size())); 453``` 454 455### Search hash_map<string> via find_as() instead of find(). 456 457EASTL hash tables offer a bonus function called find_as when lets you search a hash table by something other than the container type. This is particularly useful for hash tables of string objects that you want to search for by string literals (e.g. "hello") or char pointers. If you search for a string via the find function, your string literal will necessarily be converted to a temporary string object, which is inefficient. 458 459To use find_as, you can use the following code: 460 461```cpp 462hash_map<string, int> hashMap; 463 464 hash_map<string, int>::iterator it = hashMap.find_as("hello"); // Using default hash and compare. 465``` 466 467### Take advantage of type_traits (e.g. EASTL_DECLARE_TRIVIAL_RELOCATE). 468 469EASTL includes a fairly serious type traits library that is on par with the one found in Boost but offers some additional performance-enhancing help as well. The type_traits library provides information about class *types*, as opposed to class instances. For example, the is_integral type trait tells if a type is one of int, short, long, char, uint64_t, etc. 470 471There are three primary uses of type traits: 472 473* Allowing for optimized operations on some data types. 474* Allowing for different logic pathways based on data types. 475* Allowing for compile-type assertions about data type expectations. 476 477Most of the type traits are automatically detected and implemented by the compiler. However, EASTL allows for the user to explicitly give the compiler hints about type traits that the compiler cannot know, via the EASTL_DECLARE declarations. If the user has a class that is relocatable (i.e. can safely use memcpy to copy values), the user can use the EASTL_DECLARE_TRIVIAL_RELOCATE declaration to tell the compiler that the class can be copied via memcpy. This will automatically significantly speed up some containers and algorithms that use that class. 478 479Here is an example of using type traits to tell if a value is a floating point value or not: 480 481```cpp 482template <typename T> 483 484 DoSomething(T t) { 485 486 assert(is_floating_point<T>::value); 487 488 } 489``` 490 491Here is an example of declaring a class as relocatable and using it in a vector. 492 493```cpp 494EASTL_DECLARE_TRIVIAL_RELOCATE(Widget); // Usually you put this at the Widget class declaration. 495 496 vector<Widget> wVector; 497 498 wVector.erase(wVector.begin()); // This operation will be optimized via using memcpy. 499``` 500 501The following is a full list of the currently recognized type traits. Most of these are implemented as of this writing, but if there is one that is missing, feel free to contact the maintainer of this library and request that it be completed. 502 503* is_void 504* is_integral 505* is_floating_point 506* is_arithmetic 507* is_fundamental 508* is_const 509* is_volatile 510* is_abstract 511* is_signed 512* is_unsigned 513* is_array 514* is_pointer 515* is_reference 516* is_member_object_pointer 517* is_member_function_pointer 518* is_member_pointer 519* is_enum 520* is_union 521* is_class 522* is_polymorphic 523* is_function 524* is_object 525* is_scalar 526* is_compound 527* is_same 528* is_convertible 529* is_base_of 530* is_empty 531* is_pod 532* is_aligned 533* has_trivial_constructor 534* has_trivial_copy 535* has_trivial_assign 536* has_trivial_destructor 537* has_trivial_relocate1 538* has_nothrow_constructor 539* has_nothrow_copy 540* has_nothrow_assign 541* has_virtual_destructor 542* alignment_of 543* rank 544* extent 545* 546<sup>1</sup> has_trivial_relocate is not found in Boost nor the C++ standard update proposal. However, it is very useful in allowing for the generation of optimized object moving operations. It is similar to the is_pod type trait, but goes further and allows non-pod classes to be categorized as relocatable. Such categorization is something that no compiler can do, as only the user can know if it is such. Thus EASTL_DECLARE_TRIVIAL_RELOCATE is provided to allow the user to give the compiler a hint. 547 548### Name containers to track memory usage. 549 550All EASTL containers which allocate memory have a built-in function called set_name and have a constructor argument that lets you specify the container name. This name is used in memory tracking and allows for the categorization and measurement of memory usage. You merely need to supply a name for your containers to use and it does the rest. 551 552Here is an example of creating a list and naming it "collision list": 553 554`list<CollisionData> collisionList(allocator("collision list"));` 555 556or 557 558```cpp 559list<CollisionData> collisionList; 560 561collisionList.get_allocator().set_name("collision list"); 562``` 563 564Note that EASTL containers do not copy the name contents but merely copy the name pointer. This is done for simplicity and efficiency. A user can get around this limitation by creating a persistently present string table. Additionally, the user can get around this by declaring static but non-const strings and modifying them at runtime. 565 566### Learn the algorithms. 567 568EASTL algorithms provide a variety of optimized implementations of fundamental algorithms. Many of the EASTL algorithms are the same as the STL algorithm set, though EASTL adds additional algorithms and additional optimizations not found in STL implementations such as Microsoft's. The copy algorithm, for example, will memcpy data types that have the has_trivial_relocate type trait instead of doing an element-by-element copy. 569 570The classifications we use here are not exactly the same as found in the C++ standard; they have been modified to be a little more intuitive. Not all the functions listed here may be yet available in EASTL as you read this. If you want some function then send a request to the maintainer. Detailed documentation for each algorithm is found in algorithm.h or the otherwise corresponding header file for the algorithm. 571 572**Search** 573 574* find, find_if 575* find_end 576* find_first_of 577* adjacent_find 578* binary_search 579* search, search_n 580* lower_bound 581* upper_bound 582* equal_range 583 584**Sort** 585 586* is_sorted 587* quick_sort 588* insertion_sort 589* shell_sort 590* heap_sort 591* merge_sort, merge_sort_buffer 592* merge 593* inplace_merge 594* partial_sort 595* stable_sort 596* partial_sort_copy 597* <other sort functions found in the EASTL bonus directories> 598 599**Modifying** 600 601* fill, fill_n 602* generate, generate_n 603* random_shuffle 604* swap 605* iter_swap 606* swap_ranges 607* remove, remove_if 608* remove_copy, remove_copy_if 609* replace, replace_if 610* replace_copy, replace_copy_if 611* reverse 612* reverse_copy 613* rotate 614* rotate_copy 615* partition 616* stable_partition 617* transform 618* next_permutation 619* prev_permutation 620* unique 621* unique_copy 622 623**Non-Modifying** 624 625* for_each 626* copy 627* copy_backward 628* count, count_if 629* equal 630* mismatch 631* min 632* max 633* min_element 634* max_element 635* lexicographical_compare 636* nth_element 637 638**Heap** 639 640* is_heap 641* make_heap 642* push_heap 643* pop_heap 644* change_heap 645* sort_heap 646* remove_heap 647 648**Set** 649 650* includes 651* set_difference 652* set_symmetric_difference 653* set_intersection 654* set_union 655 656### Pass and return containers by reference instead of value. 657 658If you aren't paying attention you might accidentally write code like this: 659 660```cpp 661void DoSomething(list<Widget> widgetList) { 662 663 ... 664 665} 666``` 667 668The problem with the above is that widgetList is passed by value and not by reference. Thus the a copy of the container is made and passed instead of a reference of the container being passed. This may seem obvious to some but this happens periodically and the compiler gives no warning and the code will often execute properly, but inefficiently. Of course there are some occasions where you really do want to pass values instead of references. 669 670### Consider using reset() for fast container teardown. 671 672EASTL containers have a reset function which unilaterally resets the container to a newly constructed state. The contents of the container are forgotten; no destructors are called and no memory is freed. This is a risky but power function for the purpose of implementing very fast temporary containers. There are numerous cases in high performance programming when you want to create a temporary container out of a scratch buffer area, use the container, and then just "vaporize" it, as it would be waste of time to go through the trouble of clearing the container and destroying and freeing the objects. Such functionality is often used with hash tables or maps and with a stack allocator (a.k.a. linear allocator). 673 674Here's an example of usage of the reset function and a PPMalloc-like StackAllocator: 675 676```cpp 677pStackAllocator->push_bookmark(); 678 679 hash_set<Widget, less<Widget>, StackAllocator> wSet(pStackAllocator); 680 681<use wSet> 682 683 wSet.reset(); 684 685 pStackAllocator->pop_bookmark(); 686``` 687 688### Consider using fixed_substring instead of copying strings. 689 690EASTL provides a fixed_substring class which uses a reference to a character segment instead of allocating its own string memory. This can be a more efficient way to work with strings under some circumstances. 691 692Here's an example of usage of fixed_substring: 693 694```cpp 695basic_string<char> str("hello world"); 696 697 fixed_substring<char> sub(str, 6, 5); // sub == "world" 698 699fixed_substring can refer to any character array and not just one that derives from a string object. 700``` 701 702### Consider using vector::push_back(void). 703 704EASTL provides an alternative way to insert elements into containers that avoids copy construction and/or the creation of temporaries. Consider the following code: 705 706```cpp 707vector<Widget> widgetArray; 708 709 widgetArray.push_back(Widget()); 710``` 711 712The standard vector push_back function requires you to supply an object to copy from. This incurs the cost of the creation of a temporary and for some types of classes or situations this cost may be undesirable. It additionally requires that your contained class support copy-construction whereas you may not be able to support copy construction. As an alternative, EASTL provides a push_back(void) function which requires nothing to copy from but instead constructs the object in place in the container. So you can do this: 713 714```cpp 715vector<Widget> widgetArray; 716 717 widgetArray.push_back(); 718 719widgetArray.back().x = 0; // Example of how to reference the new object. 720``` 721 722Other containers with such copy-less functions include: 723 724```cpp 725vector::push_back() 726 727 deque::push_back() 728 729 deque::push_front() 730 731 list::push_back() 732 733 list::push_front() 734 735 slist::push_front() 736 737 map::insert(const key_type& key) 738 739 multimap::insert(const key_type& key) 740 741 hash_map::insert(const key_type& key) 742 743 hash_multimap::insert(const key_type& key) 744``` 745 746Note that the map functions above allow you to insert a default value specified by key alone and not a value_type like with the other map insert functions. 747 748---------------------------------------------- 749End of document 750