├── LICENSE ├── README.md ├── additional_stl.md ├── binary_search.md ├── c.md ├── c_notes.md ├── cpp_notes.md ├── pointer.md ├── stl.md └── thread.md /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # C/C++ STL Quick Guide 2 | 3 | 4 | ### C/C++ 5 | 6 | | Topics | README | 7 | | ------ | ------ | 8 | | Pointers | [POINTER.md](https://github.com/iRajul/cpp-stl-quick-guide/blob/master/pointer.md) | 9 | | Effective STL | [STL.md](https://github.com/iRajul/cpp-stl-quick-guide/blob/master/stl.md) | 10 | | C Notes | [C Notes](https://github.com/iRajul/cpp-stl-quick-guide/blob/master/c_notes.md) | 11 | | C++ Notes | [C++ Notes](https://github.com/iRajul/cpp-stl-quick-guide/blob/master/cpp_notes.md) | 12 | | Thread Notes | [Thread Notes](https://github.com/iRajul/cpp-stl-quick-guide/blob/master/thread.md) | 13 | -------------------------------------------------------------------------------- /additional_stl.md: -------------------------------------------------------------------------------- 1 | 2 | ## Container Adapter 3 | ### priority_queue : 4 | template< class T, class Container = std::vector, class Compare = std::less > class priority_queue 5 | 6 | - `vector` and `deque` can be used as container. 7 | - By default it is max 8 | heap, can be converted into min heap using `greater` comparator. 9 | - `push()` -> Effectively calls c.push_back(value); 10 | std::push_heap(c.begin(), c.end(), comp); 11 | - `pop()` -> 12 | std::pop_heap(c.begin(), c.end(), comp); c.pop_back(); 13 | -------------------------------------------------------------------------------- /binary_search.md: -------------------------------------------------------------------------------- 1 | ### Binary Search 2 | ### Problem 1 (Simple Version) 3 | ```cpp 4 | int binary_search(int[] nums, int target) { 5 | int left = 0, right = nums.length - 1; 6 | while(left <= right) { 7 | int mid = left + (right - left) / 2; 8 | if (nums[mid] < target) { 9 | left = mid + 1; 10 | } else if (nums[mid] > target) { 11 | right = mid - 1; 12 | } else if(nums[mid] == target) { 13 | // Return directly 14 | return mid; 15 | } 16 | } 17 | // Return directly 18 | return -1; 19 | } 20 | ``` 21 | ### Left Bound (minimize mid for which condition remains true) 22 | For such kind of problems where we need to minimize mid so as to satisfy a condition. 23 | ```cpp 24 | int left_bound(int[] nums) { 25 | int left = 0, right = nums.length - 1; 26 | while (left <= right) { 27 | int mid = left + (right - left) / 2; 28 | if (condition(mid)) { 29 | right = mid - 1; //Shrink right side. 30 | } else 31 | left = mid + 1; 32 | } 33 | } 34 | return left; 35 | } 36 | ``` 37 | ### Problem 2.a 38 | Find left most position of target in sorted array. 39 | What should be condition here? 40 | We need to find minimum `mid` position for which `arr[mid] >= target`. 41 | so, simply apply above template. 42 | ```cpp 43 | int left_bound(int[] nums) { 44 | int left = 0, right = nums.length - 1; 45 | while (left <= right) { 46 | int mid = left + (right - left) / 2; 47 | if (nums[mid] >= target) { 48 | right = mid -1; //Shrink right side. 49 | } else 50 | left = mid + 1; 51 | } 52 | } 53 | if (left >= nums.size() || nums[left] != target) 54 | return -1; 55 | return left; 56 | } 57 | ``` 58 | ### Problem 2.b 59 | https://leetcode.com/problems/search-insert-position/ 60 | 61 | 62 | 63 | ### Problem 3 (Right Bound) (maximize mid for which condition remains true) 64 | ```cpp 65 | int right_bound(int[] nums, int target) { 66 | int left = 0, right = nums.length - 1; 67 | while (left <= right) { 68 | int mid = left + (right - left) / 2; 69 | if (condition(mid)) { 70 | left = mid + 1; // Shrink left side 71 | } else { 72 | right = mid - 1; 73 | } 74 | } 75 | return right; 76 | } 77 | ``` 78 | 79 | ### Problem 3.a 80 | Find right most position of target in sorted array. 81 | What should be condition here? 82 | We need to find maximum `mid` position for which `arr[mid] <= target`. 83 | so, simply apply above template. 84 | ```cpp 85 | int right_bound(int[] nums) { 86 | int left = 0, right = nums.length - 1; 87 | while (left <= right) { 88 | int mid = left + (right - left) / 2; 89 | if (nums[mid] <= target) { 90 | left = mid + 1; //Shrink left side. 91 | } else { 92 | right = mid - 1; 93 | } 94 | } 95 | if (right < 0 || nums[right] != target) 96 | return -1; 97 | return right; 98 | } 99 | ``` 100 | 101 | Reference : 102 | https://labuladong.gitbook.io/algo-en/iii.-algorithmic-thinking/detailedbinarysearch 103 | https://leetcode.com/problems/koko-eating-bananas/discuss/769702/Python-Clear-explanation-Powerful-Ultimate-Binary-Search-Template.-Solved-many-problems 104 | -------------------------------------------------------------------------------- /c.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /c_notes.md: -------------------------------------------------------------------------------- 1 | 1. Is it fine to write “void main()” or “main()” in C/C++? 2 | 3 | 4 | 2. Difference between “int main()” and “int main(void)” in C/C++? 5 | So the difference is, in C, int main() can be called with any number of arguments, but int main(void) can only be called without any argument. Although it doesn’t make any difference most of the times, using “int main(void)” is a recommended practice in C. 6 | 7 | 8 | 3. Interesting Facts about Macros and Preprocessors in C 9 | In a C program, all lines that start with `#` are processed by preprocessor which is a special program invoked by the compiler. In a very basic term, preprocessor takes a C program and produces another C program without any `#`. 10 | 11 | Following are some interesting facts about preprocessors in C. 12 | 1) When we use include directive, the contents of included header file (after preprocessing) are copied to the current file. Angular brackets < and > instruct the preprocessor to look in the standard folder where all header files are held. Double quotes “ and “ instruct the preprocessor to look into the current folder and if the file is not present in current folder, then in standard folder of all header files. 13 | 2) When we use define for a constant, the preprocessor produces a C program where the defined constant is searched and matching tokens are replaced with the given expression. For example in the following program max is defined as 100. 14 | 3) The macros can take function like arguments, the arguments are not checked for data type. For example, the following macro INCREMENT(x) can be used for x of any data type. 15 | ``` 16 | #include 17 | #define INCREMENT(x) ++x 18 | int main() 19 | { 20 | char *ptr = "GeeksQuiz"; 21 | int x = 10; 22 | printf("%s ", INCREMENT(ptr)); 23 | printf("%d", INCREMENT(x)); 24 | return 0; 25 | } 26 | // Output: eeksQuiz 11 27 | ``` 28 | 29 | 4) The macro arguments are not evaluated before macro expansion. For example consider the following program 30 | ``` 31 | #define MULTIPLY(a, b) a*b 32 | int main() 33 | { 34 | // The macro is expended as 2 + 3 * 3 + 5, not as 5*8 35 | printf("%d", MULTIPLY(2+3, 3+5)); 36 | return 0; 37 | } 38 | // Output: 16 39 | ``` 40 | 41 | 5) The tokens passed to macros can be concatenated using operator `##` called Token-Pasting operator. 42 | ``` 43 | #include 44 | #define merge(a, b) a##b 45 | int main() 46 | { 47 | printf("%d ", merge(12, 34)); 48 | } 49 | // Output: 1234 50 | ``` 51 | 52 | 6) A token passed to macro can be converted to a sting literal by using `#` before it. 53 | ``` 54 | #include 55 | #define get(a) #a 56 | int main() 57 | { 58 | // GeeksQuiz is changed to "GeeksQuiz" 59 | printf("%s", get(GeeksQuiz)); 60 | } 61 | // Output: GeeksQuiz 62 | ``` 63 | 64 | 65 | 7) The macros can be written in multiple lines using ‘\’. The last line doesn’t need to have ‘\’. 66 | ``` 67 | #include 68 | #define PRINT(i, limit) while (i < limit) \ 69 | { \ 70 | printf("GeeksQuiz "); \ 71 | i++; \ 72 | } 73 | int main() 74 | { 75 | int i = 0; 76 | PRINT(i, 3); 77 | return 0; 78 | } 79 | // Output: GeeksQuiz GeeksQuiz GeeksQuiz 80 | ``` 81 | 82 | 8) The macros with arguments should be avoided as they cause problems sometimes. And Inline functions should be preferred as there is type checking parameter evaluation in inline functions. From C99 onward, inline functions are supported by C language also. 83 | For example consider the following program. From first look the output seems to be 1, but it produces 36 as output. 84 | ``` 85 | #define square(x) x*x 86 | int main() 87 | { 88 | int x = 36/square(6); // Expended as 36/6*6 89 | printf("%d", x); 90 | return 0; 91 | } 92 | // Output: 36 93 | ``` 94 | If we use inline functions, we get the expected output. Also the program given in point 4 above can be corrected using inline functions. 95 | ``` 96 | inline int square(int x) { return x*x; } 97 | 36/square(6); 36/6*6 98 | ``` 99 | 9) Preprocessors also support if-else directives which are typically used for conditional compilation. 100 | ``` 101 | int main() 102 | { 103 | #if VERBOSE >= 2 104 | printf("Trace Message"); 105 | #endif 106 | } 107 | ``` 108 | 109 | 10) A header file may be included more than one time directly or indirectly, this leads to problems of redeclaration of same variables/functions. To avoid this problem, directives like defined, ifdef and ifndef are used. 110 | 111 | 11) There are some standard macros which can be used to print program file (__FILE__), Date of compilation (__DATE__), Time of compilation (__TIME__) and Line Number in C code (__LINE__) 112 | 113 | * What’s difference between “array” and “&array” for “int array[5]” ? 114 | Basically, “array” is a “pointer to the first element of array” but “&array” is a “pointer to whole array of 5 int”. Since “array” is pointer to int, addition of 1 resulted in an address with increment of 4 (assuming int size in your machine is 4 bytes). Since “&array” is pointer to array of 5 ints, addition of 1 resulted in an address with increment of 4 x 5 = 20 = 0x14. 115 | 116 | 117 | * What is NULL pointer 118 | * sizeof NULL 119 | * sizeof void 120 | * sizeof void* 121 | 122 | 123 | #### Struct: 124 | A structure is a user defined data type in C/C++. A structure creates a data type that can be used to group items of possibly different types into a single type. 125 | 126 | ##### Structure padding 127 | There is a way to minimize padding. The programmer should declare the structure members in their increasing/decreasing order of size. 128 | 129 | ```typedef struct structd_tag 130 | { 131 | double d; 132 | int s; 133 | char c; 134 | } structd_t; 135 | ``` 136 | `sizeof(structd_tag) = 16;` 137 | 138 | compiler introduces alignment requirement to every structure. It will be as that of the largest member of the structure. i.e final size of structure should be multiple of largest data type size in structure. In above case 16 is a mulitple of 8. 139 | 140 | #### Union: 141 | Like Structures, union is a user defined data type. In union, all members share the same memory location. 142 | 143 | For example in the following C program, both x and y share the same location. If we change x, we can see the changes being reflected in y. Size of a union is taken according the size of largest member in union. 144 | 145 | ``` 146 | #include 147 | 148 | // Declaration of union is same as structures 149 | union test 150 | { 151 | int x, y; 152 | }; 153 | ``` 154 | 155 | #### What are applications of union? 156 | TODO 157 | 158 | #### Struct Hack (flexible array members) 159 | What will be the size of following structure? 160 | ``` 161 | struct employee 162 | { 163 | int emp_id; 164 | int name_len; 165 | char name[0]; 166 | }; 167 | ``` 168 | `4 + 4 + 0 = 8 bytes.` 169 | 170 | And what about size of `“name[0]”`. In gcc, when we create an array of zero length, it is considered as array of incomplete type that’s why gcc reports its size as “0” bytes. This technique is known as “Stuct Hack”. When we create array of zero length inside structure, it must be (and only) last member of structure. 171 | “Struct Hack” technique is used to create variable length member in a structure. 172 | 173 | Let us see below memory allocation. 174 | 175 | `struct employee *e = malloc(sizeof(*e) + sizeof(char) * 128); ` 176 | is equivalent to 177 | 178 | ``` 179 | struct employee 180 | { 181 | int emp_id; 182 | int name_len; 183 | char name[128]; /* character array of size 128 */ 184 | }; 185 | ``` 186 | And below memory allocation 187 | 188 | `struct employee *e = malloc(sizeof(*e) + sizeof(char) * 1024); ` 189 | is equivalent to 190 | ``` 191 | struct employee 192 | { 193 | int emp_id; 194 | int name_len; 195 | char name[1024]; /* character array of size 1024 */ 196 | }; 197 | ``` 198 | Other advantage of this is, suppose if we want to write data, we can write whole data by using single “write()” call. e.g. 199 | 200 | `write(fd, e, sizeof(*e) + name_len); /* write emp_id + name_len + name */ ` 201 | 202 | 203 | #### Bit Fields in C: 204 | In C, we can specify size (in bits) of structure and union members. 205 | ``` 206 | #include 207 | 208 | // A space optimized representation of date 209 | struct date 210 | { 211 | // d has value between 1 and 31, so 5 bits 212 | // are sufficient 213 | unsigned int d: 5; 214 | 215 | // m has value between 1 and 12, so 4 bits 216 | // are sufficient 217 | unsigned int m: 4; 218 | 219 | unsigned int y; 220 | }; 221 | ``` 222 | 223 | size of above structure is 8 224 | 225 | 1) A special unnamed bit field of size 0 is used to force alignment on next boundary. For example consider the following program. 226 | unsigned int : 0; 227 | 2) We cannot have pointers to bit field members as they may not start at a byte boundary. 228 | &date.m is not allowed 229 | 3) It is implementation defined to assign an out-of-range value to a bit field member. 230 | 4) In C++, we can have static members in a structure/class, but bit fields cannot be static. 231 | static unsigned int x: 5;(not allowed) 232 | 5) Array of bit fields is not allowed. For example, the below program fails in compilation. 233 | `unsigned int x[10]: 5;(not allowed )` 234 | 235 | #### Storage Classes in C 236 | 1. auto 237 | 2. extern 238 | 3. static 239 | 4. register 240 | 241 | #### Static in C 242 | * Static variable and function 243 | * Initialization of static variables in C 244 | static int i = 50; 245 | 246 | 247 | #### Understanding “volatile” qualifier in C 248 | The volatile keyword is intended to prevent the compiler from applying any optimizations on objects that can change in ways that cannot be determined by the compiler. 249 | 1) Global variables modified by an interrupt service routine outside the scope 250 | 2) Global variables within a multi-threaded application 251 | 252 | Example: 253 | ``` 254 | const int local = 10; 255 | int *ptr = (int*) &local; 256 | printf("Initial value of local : %d \n", local); 257 | *ptr = 100; 258 | ``` 259 | 260 | ------------------------------------------------ 261 | 262 | #### Memory layout of c program: 263 | TODO 264 | 265 | Dynamic Memory allocation in C: 266 | * malloc 267 | * calloc 268 | * realloc 269 | * Use of realloc() 270 | `void *realloc(void *ptr, size_t size);` 271 | 272 | #### File management: 273 | * fseek() vs rewind() in C 274 | `fseek()` sets the file position indicator of an input stream back to the beginning using rewind(). But there is no way to check whether the rewind() was successful. 275 | ``` 276 | if(fseek(fp, 0L, SEEK_BEG) != 0){ 277 | //handle error 278 | } 279 | ``` 280 | * EOF, getc() and feof() in C 281 | getc() can return EOF if any error occurs. 282 | `foef()` is better choice. 283 | ``` 284 | if (feof(fp)) 285 | printf("\n End of file reached."); 286 | else 287 | printf("\n Something went wrong."); 288 | ``` 289 | 290 | * fopen() for an existing file in write mode (wx mode like w) 291 | * fgets() and gets() in C language 292 | For reading a string value with spaces, we can use either gets() or fgets() in C programming language. Here, we will see what is the difference between gets() and fgets(). 293 | `fgets(char*, int n, FILE*);` 294 | `gets(char*);` 295 | There is no error array bound check in `gets()`; 296 | gets() is risky to use! 297 | it suffers from Buffer Overflow as gets() doesn’t do any array bound testing: 298 | 299 | * use fgets 300 | ``` 301 | char str[MAX_LIMIT]; 302 | fgets(str, MAX_LIMIT, stdin); 303 | ``` 304 | 305 | #### return statement vs exit() in main() 306 | When exit(0) is used to exit from program, destructors for locally scoped non-static objects are not called. But destructors are called if return 0 is used. 307 | Calling destructors is sometimes important, for example, if destructor has code to release resources like closing files. 308 | 309 | 310 | #### little endian and big endian 311 | TODO 312 | 313 | 314 | 315 | 316 | #### Internal and external linkage: 317 | **external linkage** means the symbol (function or global variable) is accessible throughout your program and **internal linkage** means that it's only accessible in one translation unit. 318 | 319 | You can explicitly control the linkage of a symbol by using the extern and static keywords. If the linkage isn't specified then the default linkage is extern for non-const symbols and static (internal) for const symbols. 320 | 321 | Example: 322 | ``` 323 | // in namespace or global scope 324 | int i; // extern by default 325 | const int ci; // static by default 326 | extern const int eci; // explicitly extern 327 | static int si; // explicitly static 328 | 329 | // the same goes for functions (but there are no const functions) 330 | int foo(); // extern by default 331 | static int bar(); // explicitly static 332 | ``` 333 | 334 | 335 | 336 | 337 | 338 | -------------------------------------------------------------------------------- /cpp_notes.md: -------------------------------------------------------------------------------- 1 | #### Internal and external linkage via the static and extern keywords 2 | A variable with internal linkage is called an internal variable (or static variable). Variables with internal linkage can be used anywhere within the file they are defined in, but can not be referenced outside the file they exist in. 3 | 4 | A variable with external linkage is called an external variable. Variables with external linkage can be used both in the file they are defined in, as well as in other files. 5 | If we want to make a global variable internal (able to be used only within a single file), we can use the static keyword to do so: 6 | 7 | ``` 8 | static int g_x; // g_x is static, and can only be used within this file 9 | ``` 10 | Similarly, if we want to make a global variable external (able to be used anywhere in our program), we can use the extern keyword to do so: 11 | 12 | 13 | ``` 14 | extern double g_y(9.8); // g_y is external, and can be used by other files 15 | ``` 16 | 17 | By default, non-const variables declared outside of a block are assumed to be external. However, const variables declared outside of a block are assumed to be internal. 18 | 19 | #### File scope vs. global scope 20 | 21 | The terms “file scope” and “global scope” tend to cause confusion, and this is partly due to the way they are informally used. Technically, in C++, all global variables in C++ have “file scope”. However, informally, the term “file scope” is more often applied to file scope variables with internal linkage only, and “global scope” to file scope variables with external linkage. 22 | 23 | Consider the following program: 24 | 25 | ``` 26 | global.cpp: 27 | 28 | 29 | int g_x(2); // external linkage by default 30 | 31 | main.cpp: 32 | 33 | 34 | extern int g_x; // forward declaration for g_x -- g_x can be used beyond this point in this file 35 | 36 | int main() 37 | 38 | { 39 | 40 | std::cout << g_x; // should print 2 41 | 42 | return 0; 43 | 44 | } 45 | ``` 46 | `g_x` has file scope within `global.cpp` -- it can not be directly seen outside of global.cpp. Note that even though it’s used in main.cpp, main.cpp isn’t seeing g_x, it’s seeing the forward declaration of g_x (which also has file scope). The linker is responsible for linking up the definition of g_x in global.cpp with the use of g_x in main.cpp. 47 | 48 | 49 | #### Quiz 50 | 1) What’s the difference between a variable’s scope, duration, and linkage? What kind of scope, duration, and linkage do global variables have? 51 | 52 | Scope determines where a variable is accessible. Duration determines where a variable is created and destroyed. Linkage determines whether the variable can be exported to another file or not. 53 | 54 | Global variables have global scope (aka. file scope), which means they can be accessed from the point of declaration to the end of the file in which they are declared. 55 | 56 | Global variables have static duration, which means they are created when the program is started, and destroyed when it ends. 57 | 58 | Global variables can have either internal or external linkage, via the static and extern keywords respectively. 59 | 60 | 61 | 62 | 2) What is a namespace? 63 | 64 | * A namespace defines an area of code in which all identifiers are guaranteed to be unique. 65 | 66 | #### operator overloading: 67 | 1. using friend 68 | 2. normal function 69 | 3. member function. 70 | 71 | 72 | * Not everything can be overloaded as a friend function 73 | 74 | * The `assignment (=), subscript ([]), function call (()), and member selection (->) operators` must be overloaded as member functions, because the language requires them to be. 75 | 76 | * The following rules of thumb can help you determine which form is best for a given situation: 77 | * If you’re overloading assignment (=), subscript ([]), function call (()), or member selection (->), do so as a member function. 78 | * If you’re overloading a unary operator, do so as a member function. 79 | * If you’re overloading a binary operator that modifies its left operand (e.g. operator+=), do so as a member function if you can. 80 | * If you’re overloading a binary operator that does not modify its left operand (e.g. operator+), do so as a normal function or friend function. 81 | 82 | 83 | * overlaod post and preincrement operator ++ and -- 84 | 85 | * dont call subscript operator on pointer to an object. 86 | ``` 87 | IntList *list = new IntList; 88 | list [2] = 3; // error: this will assume we're accessing index 2 of an array of IntLists 89 | ``` 90 | * Direct, uniform and copy initialization. 91 | 92 | * conversion constructor which take atleast one parameter. 93 | 94 | 95 | #### Function Overloading and float in C++: 96 | As per C++ standard, floating point literals (compile time constants) are treated as double unless explicitly specified by a suffix 97 | 98 | 99 | #### Does overloading work with Inheritance? 100 | Overloading doesn’t work for derived class in C++ programming language. There is no overload resolution between Base and Derived. The compiler looks into the scope of Derived. 101 | q 102 | 103 | #### Size of array without sizeof operator 104 | ``` 105 | int arr[6]; 106 | int size = *(&arr + 1) - arr; 107 | ``` 108 | 109 | ``` 110 | &arr ==> Pointer to an array of 6 elements. 111 | 112 | (&arr + 1) ==> Address of 6 integers ahead as 113 | pointer type is pointer to array 114 | of 6 integers. 115 | 116 | *(&arr + 1) ==> Same address as (&arr + 1), but 117 | type of pointer is "int *". 118 | 119 | *(&arr + 1) - arr ==> Since *(&arr + 1) points 120 | to the address 6 integers 121 | ahead of arr, the difference 122 | between two is 6. 123 | ``` 124 | 125 | #### Inheritance and Composition 126 | 3 types of relationships: composition, aggregation, and association. 127 | 128 | relationship - Dependencies 129 | A dependency occurs when one object invokes another object’s functionality in order to accomplish some specific task. This is a weaker relationship than an association, but still, any change to the dependent object may break functionality in the caller. A dependency is always a unidirectional relationship. 130 | example : Our classes that use std::cout use it in order to accomplish the task of printing something to the console, but not otherwise. 131 | 132 | 133 | Change access specifier of class: 134 | you can change access specifier of base memeber the derived class would normally be able to access. 135 | 136 | #### Multiple inheritance problem. 137 | 1. Ambiguity in calling function with same name which are present in multiple base classes 138 | 2. Diamond problem. (solution using virtual base.) 139 | 140 | * Dont call virtual function from construtor and destructor. 141 | * use override and final 142 | * object slicing and frakenobject. 143 | ``` 144 | int main() 145 | { 146 | Derived d1(5); 147 | Derived d2(6); 148 | Base &b = d2; 149 | b = d1; // this line is problematic 150 | return 0; 151 | } 152 | ``` 153 | Only base class part get copied because `operator=` is not virtual by default. 154 | * We cannot have references in vector . 155 | 156 | #### dynamic_cast 157 | * dynamic_cast is not possible with protected and private inhertiance and class without virtual function. 158 | * dynamic_cast with references throw a std::bad_cast instead of returning NULL; 159 | * Difference b/w dynamic and static cast : https://stackoverflow.com/a/2254183/1622022 160 | 161 | 162 | ##### Reference to dynamic memory allocation : 163 | int& foo = *(new int); 164 | 165 | l-values are objects that have a defined memory address (such as variables), and persist beyond a single expression. r-values are temporary values that do not have a defined memory address, and only have expression scope. 166 | 167 | References to r-values extend the lifetime of the referenced value 168 | ``` 169 | int somefcn() 170 | { 171 | const int &ref = 2 + 3; // normally the result of 2+3 has expression scope and is destroyed at the end of this statement 172 | // but because the result is now bound to a reference to a const value... 173 | std::cout << ref; // we can use it here 174 | } // and the lifetime of the r-value is extended to here, when the const reference dies 175 | ``` 176 | #### Some Quick Points 177 | 178 | * because the void pointer does not know what type of object it is pointing to, it cannot be dereferenced directly! 179 | `cout << *voidPtr << endl; // illegal: cannot dereference a void pointer` 180 | 181 | * Function return types are not considered for uniqueness for overloading 182 | 183 | * all literal floating point values are doubles unless they have the ‘f’ suffix 184 | 185 | #### How function calls are matched with overloaded functions 186 | 187 | 1) First, C++ tries to find an exact match. This is the case where the actual argument exactly matches the parameter type of one of the overloaded functions. For example: 188 | ``` 189 | void print(char *value); 190 | void print(int value) 191 | ``` 192 | 193 | 2) If no exact match is found, C++ tries to find a match through promotion. 194 | Char, unsigned char, and short is promoted to an int. 195 | Unsigned short can be promoted to int or unsigned int, depending on the size of an int 196 | Float is promoted to double 197 | Enum is promoted to int 198 | 199 | * The default constructor allows us to create objects of the class, but does not do any initialization or assignment of values to the class members itself. 200 | 201 | * you could initialize class variables in three ways: copy, direct, and via uniform initialization 202 | `Fraction six = Fraction(6);` 203 | `Fraction six(6);` 204 | 205 | * Initializing array members with member initializer lists 206 | `Something(): m_array {} // zero the member array` 207 | 208 | * Member initializer lists allow us to initialize our members rather than assign values to them. This is the only way to initialize members that require values upon initialization, such as **const or reference members**, and it can be more performant than assigning values in the body of the constructor. Member initializer lists work both with fundamental types and members that are classes themselves. 209 | 210 | * if we make each function return *this, we can chain the calls together 211 | 212 | 213 | -------------------------------------------------------------------------------- /pointer.md: -------------------------------------------------------------------------------- 1 | What the hell is pointers? 2 | ``` 3 | The "right-left" rule is a completely regular rule for deciphering C 4 | declarations. It can also be useful in creating them. 5 | 6 | First, symbols. Read 7 | 8 | * as "pointer to" - always on the left side 9 | [] as "array of" - always on the right side 10 | () as "function returning" - always on the right side 11 | 12 | as you encounter them in the declaration. 13 | 14 | STEP 1 15 | ------ 16 | Find the identifier. This is your starting point. Then say to yourself, 17 | "identifier is." You've started your declaration. 18 | 19 | STEP 2 20 | ------ 21 | Look at the symbols on the right of the identifier. If, say, you find "()" 22 | there, then you know that this is the declaration for a function. So you 23 | would then have "identifier is function returning". Or if you found a 24 | "[]" there, you would say "identifier is array of". Continue right until 25 | you run out of symbols *OR* hit a *right* parenthesis ")". (If you hit a 26 | left parenthesis, that's the beginning of a () symbol, even if there 27 | is stuff in between the parentheses. More on that below.) 28 | 29 | STEP 3 30 | ------ 31 | Look at the symbols to the left of the identifier. If it is not one of our 32 | symbols above (say, something like "int"), just say it. Otherwise, translate 33 | it into English using that table above. Keep going left until you run out of 34 | symbols *OR* hit a *left* parenthesis "(". 35 | 36 | Now repeat steps 2 and 3 until you've formed your declaration. Here are some 37 | examples: 38 | 39 | int *p[]; 40 | 41 | 1) Find identifier. int *p[]; 42 | ^ 43 | "p is" 44 | 45 | 2) Move right until out of symbols or right parenthesis hit. 46 | int *p[]; 47 | ^^ 48 | "p is array of" 49 | 50 | 3) Can't move right anymore (out of symbols), so move left and find: 51 | int *p[]; 52 | ^ 53 | "p is array of pointer to" 54 | 55 | 4) Keep going left and find: 56 | int *p[]; 57 | ^^^ 58 | "p is array of pointer to int". 59 | (or "p is an array where each element is of type pointer to int") 60 | 61 | Another example: 62 | 63 | int *(*func())(); 64 | 65 | 1) Find the identifier. int *(*func())(); 66 | ^^^^ 67 | "func is" 68 | 69 | 2) Move right. int *(*func())(); 70 | ^^ 71 | "func is function returning" 72 | 73 | 3) Can't move right anymore because of the right parenthesis, so move left. 74 | int *(*func())(); 75 | ^ 76 | "func is function returning pointer to" 77 | 78 | 4) Can't move left anymore because of the left parenthesis, so keep going 79 | right. int *(*func())(); 80 | ^^ 81 | "func is function returning pointer to function returning" 82 | 83 | 5) Can't move right anymore because we're out of symbols, so go left. 84 | int *(*func())(); 85 | ^ 86 | "func is function returning pointer to function returning pointer to" 87 | 88 | 6) And finally, keep going left, because there's nothing left on the right. 89 | int *(*func())(); 90 | ^^^ 91 | "func is function returning pointer to function returning pointer to int". 92 | 93 | 94 | As you can see, this rule can be quite useful. You can also use it to 95 | sanity check yourself while you are creating declarations, and to give 96 | you a hint about where to put the next symbol and whether parentheses 97 | are required. 98 | 99 | Some declarations look much more complicated than they are due to array 100 | sizes and argument lists in prototype form. If you see "[3]", that's 101 | read as "array (size 3) of...". If you see "(char *,int)" that's read 102 | as "function expecting (char *,int) and returning...". Here's a fun 103 | one: 104 | 105 | int (*(*fun_one)(char *,double))[9][20]; 106 | 107 | I won't go through each of the steps to decipher this one. 108 | 109 | Ok. It's: 110 | 111 | "fun_one is pointer to function expecting (char *,double) and 112 | returning pointer to array (size 9) of array (size 20) of int." 113 | 114 | As you can see, it's not as complicated if you get rid of the array sizes 115 | and argument lists: 116 | 117 | int (*(*fun_one)())[][]; 118 | 119 | You can decipher it that way, and then put in the array sizes and argument 120 | lists later. 121 | 122 | Some final words: 123 | 124 | It is quite possible to make illegal declarations using this rule, 125 | so some knowledge of what's legal in C is necessary. For instance, 126 | if the above had been: 127 | 128 | int *((*fun_one)())[][]; 129 | 130 | it would have been "fun_one is pointer to function returning array of array of 131 | ^^^^^^^^^^^^^^^^^^^^^^^^ 132 | pointer to int". Since a function cannot return an array, but only a 133 | pointer to an array, that declaration is illegal. 134 | 135 | 136 | Illegal combinations include: 137 | 138 | []() - cannot have an array of functions 139 | ()() - cannot have a function that returns a function 140 | ()[] - cannot have a function that returns an array 141 | 142 | In all the above cases, you would need a set of parens to bind a * 143 | symbol on the left between these () and [] right-side symbols in order 144 | for the declaration to be legal. 145 | 146 | Here are some legal and illegal examples: 147 | 148 | int i; an int 149 | int *p; an int pointer (ptr to an int) 150 | int a[]; an array of ints 151 | int f(); a function returning an int 152 | int **pp; a pointer to an int pointer (ptr to a ptr to an int) 153 | int (*pa)[]; a pointer to an array of ints 154 | int (*pf)(); a pointer to a function returning an int 155 | int *ap[]; an array of int pointers (array of ptrs to ints) 156 | int aa[][]; an array of arrays of ints 157 | int af[](); an array of functions returning an int (ILLEGAL) 158 | int *fp(); a function returning an int pointer 159 | int fa()[]; a function returning an array of ints (ILLEGAL) 160 | int ff()(); a function returning a function returning an int 161 | (ILLEGAL) 162 | int ***ppp; a pointer to a pointer to an int pointer 163 | int (**ppa)[]; a pointer to a pointer to an array of ints 164 | int (**ppf)(); a pointer to a pointer to a function returning an int 165 | int *(*pap)[]; a pointer to an array of int pointers 166 | int (*paa)[][]; a pointer to an array of arrays of ints 167 | int (*paf)[](); a pointer to a an array of functions returning an int 168 | (ILLEGAL) 169 | int *(*pfp)(); a pointer to a function returning an int pointer 170 | int (*pfa)()[]; a pointer to a function returning an array of ints 171 | (ILLEGAL) 172 | int (*pff)()(); a pointer to a function returning a function 173 | returning an int (ILLEGAL) 174 | int **app[]; an array of pointers to int pointers 175 | int (*apa[])[]; an array of pointers to arrays of ints 176 | int (*apf[])(); an array of pointers to functions returning an int 177 | int *aap[][]; an array of arrays of int pointers 178 | int aaa[][][]; an array of arrays of arrays of ints 179 | int aaf[][](); an array of arrays of functions returning an int 180 | (ILLEGAL) 181 | int *afp[](); an array of functions returning int pointers (ILLEGAL) 182 | int afa[]()[]; an array of functions returning an array of ints 183 | (ILLEGAL) 184 | int aff[]()(); an array of functions returning functions 185 | returning an int (ILLEGAL) 186 | int **fpp(); a function returning a pointer to an int pointer 187 | int (*fpa())[]; a function returning a pointer to an array of ints 188 | int (*fpf())(); a function returning a pointer to a function 189 | returning an int 190 | int *fap()[]; a function returning an array of int pointers (ILLEGAL) 191 | int faa()[][]; a function returning an array of arrays of ints 192 | (ILLEGAL) 193 | int faf()[](); a function returning an array of functions 194 | returning an int (ILLEGAL) 195 | int *ffp()(); a function returning a function 196 | returning an int pointer (ILLEGAL) 197 | ``` 198 | -------------------------------------------------------------------------------- /stl.md: -------------------------------------------------------------------------------- 1 | > Made this guide as a notes after reading Effective STL by scott meyers 2 | 3 | --- 4 | 5 | ### CONTAINERS 6 | 7 | ### Item 1. Choose your containers with care. 8 | 1) The standard STL sequence containers, vector, string, deque, and list. 9 | 2) The standard STL associative containers, set, multiset, map and multimap. 10 | 3) `vector` as a replacement for `string`. (Item 13) 11 | 4) vector as a replacement for the standard associative containers. (Item 23) 12 | 13 | * Contiguous-memory containers - vector, string, deque (random access iterators) 14 | * Node-based containers store only a single element per chunk : list + all associative continers. 15 | 16 | Do you need to minimize iterator, pointer, and reference invalidation? If so, you'll want to use node-based containers. 17 | 18 | --- 19 | 20 | ### Item 2. Beware the illusion of container-independent code. 21 | We strive to write container-independent code. Like writing code using vector 22 | but still preserve the option of replacing it with something like a deque or a list later. 23 | 24 | This should be avoid bcoz many methods are avialable for only one type of containers. 25 | Insert signature is different for sequence and associative containers. 26 | The different containers are different, and they have strengths and 27 | weaknesses that vary in significant ways. They're not designed to be interchangeable, 28 | 29 | ----------------------------------------------------- 30 | ### Item 3. Make copying cheap and correct for objects in containers. 31 | When you insert or get object from stl container they return copy of object. Copy in, copy out. 32 | 33 | * If you have user-defined object that has heavy copy operation, then think about it. 34 | * Objec Slicing : if you create a container of base class objects and you try to insert derived class objects into it, the derived-ness of the objects will be removed as the objects are copied (via the base class copy constructor) into the container. 35 | 36 | An easy way to make copying efficient, correct, and immune to the slicing problem is to create containers of pointers instead of containers of objects. 37 | 38 | ------------------------------------------------------ 39 | 40 | ### Item 4. Call empty() instead of checking size() against zero. 41 | * `empty` is a constant-time operation for all standard containers, but for some 42 | list implementations, `size` takes linear time. 43 | 44 | --- 45 | 46 | ### Item 5. Prefer range member functions to their single-element counterparts. 47 | 48 | Given two vectors, v1 and v2, what's the easiest way to make v1’s contents be the same as the second half of v2's? 49 | ``` 50 | // assign range flavour 51 | v1.assign(v2.begin() + v2.size() /2, v2.end()); 52 | // insert range flavour 53 | v1.insert(v1 .end(), v2.begin() + v2.size() / 2, v2.end()); 54 | ``` 55 | why use range member function? 56 | * It's generally less work to write the code using the range member functions. 57 | * Range member functions tend to lead to code that is clearer and more straightforward. 58 | * using range leads to one function call and using loop leads to n-1 extra function calls. 59 | * they are more efficient than regular loops. 60 | 61 | Range construction: All standard containers offer a constructor of this form: 62 | `container::container( Inputlterator begin, Inputlterator end);` 63 | 64 | Range insertion : 65 | 1) Sequence Container: 66 | `void container::insert(iterator position, Inputlterator begin, InputIterator end);` 67 | 2) Associative container: 68 | `void container::insert(lnputIterator begin, Inputlterator end);` 69 | Range erasure: 70 | 1) Sequence containers : 71 | `iterator container::erase(iterator begin, iterator end);` 72 | 2) Associative containers : 73 | `void container::erase(iterator begin, iterator end);` 74 | Range assignment: 75 | 1) Sequence Container: 76 | `void container::assign(lnputIterator begin, Inputlterator end);` 77 | 78 | ----------------------------------------------------- 79 | 80 | ### Item 6. Be alert for C++'s most vexing parse. 81 | TODO 82 | 83 | ----------------------------------------------------- 84 | 85 | ### Item 7. When using containers of newed pointers, remember to delete the 86 | pointers before the container is destroyed. 87 | 88 | * Either delete all elements of container using loop or use smart pointer to store elements. 89 | 90 | ----------------------------------------------------- 91 | 92 | ### Item 8. Never create containers of auto_ptrs. 93 | * `auto_ptr` transfer their ownership to caller. so never use them!! 94 | 95 | ----------------------------------------------------- 96 | 97 | ### Item 9. Choose carefully among erasing options. 98 | 99 | 1) Get rid of all the objects in c with the value 1963 100 | * For String, vector, deque 101 | `c.erase( remove(c.begin(), c.end(), 1963), c.end()); // the erase-remove idiom` 102 | 103 | * For List 104 | `c.remove(1963);` 105 | 106 | * For Associative containers: 107 | `c.erase(1963);` 108 | > the associative container erase member function has the advantage of being based on equivalence instead of equality, a distinction whose importance is explained in Item 19. 109 | 110 | 2) Eliminate every object for which the following predicate (see Item 39) returns true: 111 | * For vector, string, deque 112 | `c.erase(remove_if(c.begin(), c.end(), badValue), c.end());` 113 | 114 | * For List 115 | `c.remove_if(badValue);` 116 | 117 | * For associative containers: 118 | * Less Efficient: 119 | ``` 120 | remove_copy_if(c.begin(), c.end(), inserter( goodValues, goodValues.end()), badValue): 121 | // copy unremoved values from c to goodValues 122 | c.swap(goodValues): 123 | ``` 124 | * More efficient: 125 | ``` 126 | AssocContainer c; 127 | for (AssocContainer::iterator i = c.begin(); i != c.end(); ){ 128 | if (badValue(*I)) c.erase(i++); 129 | else ++i; 130 | } 131 | //the 3rd part of the for loop is empty; i is now incremented below for bad values, pass the current i to erase and increment i as a side effect; for good values, just increment i 132 | ``` 133 | To do something inside the loop (in addition to erasing objects): 134 | * If the container is a standard sequence container, write a loop to walk the container elements, being sure to update your iterator with erase's return value each time von call it. 135 | * If the container is a standard associative container, write a loop to walk the container elements, being sure to postincrement your iterator when you pass it to erase. 136 | 137 | --- 138 | 139 | ### Item 10 140 | TODO 141 | 142 | --- 143 | 144 | ### Item 11 145 | TODO 146 | 147 | --- 148 | 149 | ### Item 12 150 | TODO 151 | 152 | --- 153 | 154 | 155 | ### STRING AND VECTOR 156 | 157 | ### Item 13. Prefer vector and string to dynamically allocated arrays. 158 | string implementation may involve refernce counting so must see their document or use `vector` 159 | 160 | --- 161 | ### Item 14. Use reserve to avoid unnecessary reallocations. 162 | 163 | ``` 164 | vector v; 165 | v.reserve(1000); 166 | for (int i = 1; i <= 1000; ++i) v.push_back(i); 167 | ``` 168 | This should result in zero reallocations during the loop. 169 | 170 | Reallocation in vector invalidate iterators, pointer and references 171 | 172 | There are two common ways to use reserve to avoid unneeded reallocations. 173 | * The first is applicable when you know exactly or approximately how many elements will ultimately end up in your container. 174 | In that case, as in the vector code above, you simply reserve the appropriate amount of space in advance. 175 | 176 | * The second way is to reserve the maximum space you could ever need. then, once you've added all your data, trim off any excess capacity. 177 | 178 | -------------------------------------------------------- 179 | 180 | ### Item 15. Be aware of variations in string implementations. 181 | Different vendors can have different implementation of string. 182 | string objects may range in size from one to at least seven times the size of char* pointers. 183 | 184 | -------------------------------------------------------- 185 | 186 | ### Item 16. Know how to pass vector and string data to legacy APIs. 187 | For vector: 188 | ``` 189 | if (!v.empty()) { 190 | doSomething(&v[0], v.size()); 191 | } 192 | ``` 193 | > Beware : Dont use v.begin() in place of &v[0] 194 | 195 | For string: 196 | `c_str()` 197 | 198 | The approach to getting a pointer to container data that works for vectors isn't reliable for strings, because 199 | 1) the data for strings are not guaranteed to be stored in contiguous memory, and 200 | 2) the internal representation of a string is not guaranteed to end with a null character. 201 | 202 | ---------------------------------------------------------- 203 | 204 | ### Item 17. Use "the swap trick" to trim excess capacity 205 | shrink to fit : 206 | ``` 207 | vector(contestants).swap(contestants); 208 | string(s).swap(s); 209 | ``` 210 | To clear container : 211 | ``` 212 | vector v; 213 | string s; 214 | vector().swap(v); //clear v and minimize its capacity 215 | string().swap(s); // clear s and minimize its capacity 216 | ``` 217 | --- 218 | 219 | ### Item 18. Avoid using vector: 220 | Two things wrong with `vector`. 221 | First, it's not an STL container. 222 | Second, it doesn't hold bools. 223 | ``` 224 | vector v; 225 | bool *pb = &v[0]; // error! the expression on the right is of type vector::reference*, not bool* 226 | ``` 227 | Because it won't compile, `vector` fails to satisfy the requirements for STL containers. 228 | 229 | Alternative to use : 230 | * `deque // it would not allocate in contiguous manner like vector.` 231 | * `bitset` 232 | 233 | --- 234 | 235 | ### ASSOCIATIVE CONTAINER 236 | 237 | ### Item 19. Understand the difference between equality and equivalence. 238 | Equality, which is based on `operator==` 239 | Equivalence is based on the relative ordering of object values in a sorted range. 240 | `!c.key_comp()(x, y) && !c.key_comp()(y, x)` 241 | The standard associative containers are kept in sorted order, so each container must have a comparison function (less, by default) that defines how to keep things sorted. 242 | 243 | --- 244 | 245 | ### Item 20. Specify comparison types for associative containers of pointers. 246 | Anytime you create associative containers of pointers, figure you're probably going to have to specify the container's comparison type, too. 247 | Most of the time, your comparison type will just dereference the pointers and compare the pointed-to objects. 248 | ``` 249 | struct DereferenceLess { 250 | template 251 | bool operator()(PtrType pT1, // parameters are passed by 252 | PtrType pT2) const // value, because we expect them 253 | { // to be (or to act like) pointers 254 | return *pT1 < *pT2; 255 | } 256 | }; 257 | ``` 258 | 259 | Usage : `set ssp;` 260 | 261 | --------------------------------------------------------- 262 | 263 | ### Item 21. Always have comparison functions return false for equal values. 264 | 265 | --------------------------------------------------------- 266 | 267 | ### Item 22. Avoid in-place key modification in set and multiset. 268 | 269 | Key is const in map and multimap but it is non-const in set and multi-set but some vendors provide const key in set too. 270 | 271 | Dont modify key in set as it can corrupt sorting order of keys in set. 272 | If you want to modify content of key which is not a part of comparator then do it like this: 273 | ``` 274 | if (i != se.end()) { // cast away 275 | const_cast(*i).setTitle("Corporate Deity"); //constness 276 | } 277 | ``` 278 | Use "Employee&" not "Employee" because by using "Employee" it will modify temporary object not actual object. 279 | 280 | Or 281 | Follow five step process: 282 | ``` 283 | EmplDSet::iterator i = 284 | se.find(selectedlD); // Step 1: find element to change 285 | 286 | if(i!=se.end()){ 287 | Employee e(*i); // Step 2: copy the element 288 | se.erase(i++); // Step 3: remove the element; increment the iterator to maintain its validity (see Item 9) 289 | e.setTitle("Corporate Deity"); // Step 4: modify the copy 290 | se.insert(i, e); // Step 5: insert new value; hint that its location is the same as that of the 291 | } 292 | ``` 293 | ------------------------------------------------------------ 294 | 295 | ### Item 23. Consider replacing associative containers with sorted vectors. 296 | 297 | Assuming our data structures are big enough, they'll be split across multiple memory pages, but the vector will require fewer pages than the associative container. 298 | Bottom Line : 299 | Storing data in a sorted vector is likely to consume less memory than storing the same data in a standard associative container, and searching a sorted vector via binary search is likely to be faster than searching a standard associative container when page faults are taken into account. 300 | You need to write comparator for `pair` if you choose vector instead of associative container. 301 | 302 | When to use sorted vector over associative containers: 303 | your program uses the data structure in the phased manner that is first only insertions and then only lookups 304 | It makes sense to consider using a sorted vector instead of an associative container only when you know that your data structure is used in such a way that lookups are almost never mixed with insertions and erasures because inserting on sorted vector can be expensive operation. 305 | 306 | ------------------------------------------------------------- 307 | 308 | ### Item 24. Choose carefully between map::operator[] and map-insert when efficiency is important 309 | when an "add" is performed, map-insert saves you three function calls: 310 | 1) one to create a temporary default-constructed Widget object, 311 | 2) one to destruct that temporary object, and 312 | 3) one to Widget's assignment operator. 313 | 314 | `operator[]` is preferable when updating the value of an element that's already in the map. 315 | `m[k] = v; // use operator[] to update k's value to be v` 316 | 317 | `m.insert( 318 | IntWidgetMap::value_type(k, v)).first->second = v; // use insert to update k's value to be v` 319 | 320 | ------------------------------------------------------------- 321 | 322 | ### Item 25 : hash_map, hash_set 323 | 324 | TODO 325 | 326 | -------------------------------------------------------------- 327 | 328 | ### ITERATORS 329 | 330 | ### Item 26. Prefer iterator to const iterator, reverse_iterator, and const_reverse_iterator. 331 | 332 | 1) Some versions of insert and erase require iterators. 333 | * If you want to call those functions, you're going to have to produce iterators, const and reverse iterators won't do. 334 | Example : 335 | * iterator insert(iterator position, const T& x); 336 | * iterator erase(iterator position); 337 | * iterator erase(iterator rangeBegin, iterator rangeEnd); 338 | 339 | 2) It's not possible to implicitly convert a const iterator to an iterator, and 340 | the technique described in Item 27 for generating an iterator from a const_iterator is neither universally applicable nor guaranteed to be efficient. 341 | 342 | 3) Conversion from a reverse_iterator to an iterator may require iterator adjustment after the conversion. Item 28 explains when and why. 343 | 344 | 4) comparison of const iterator with non-const iterator would not compile. 345 | * if (ci == i) // not compile. 346 | * if (i == ci) // It works though 347 | 348 | -------------------------------------------------------------- 349 | 350 | ### Item 27. Use distance and advance to convert a container's const_iterators to iterators. 351 | 352 | `Iter i(const_cast(ci)); ` // It would not compile because const_iterator and iterator are of different type except for string and vector. 353 | 354 | Make a non-const iterator and move it to where const iterator is pointing. 355 | ``` 356 | // initialize i to d.begin() 357 | Iter i(d.begin()); 358 | //figure the distance between i and ci (as const_iterators), then move i that distance. 359 | advance(i, distance(i, ci)); 360 | ``` 361 | We need to specify "ConstIter" while calling distance because type of argument for distance function should be same. 362 | 363 | --- 364 | 365 | ### Item 28. Understand how to use a reverse_iterator's base iterator. 366 | 367 | Lets say there is vector of 5 element 368 | ``` 369 | |-------------------- 370 | | 1 | 2 | 3 | 4 | 5 | 371 | |-------------------- 372 | ``` 373 | 374 | ```vector::reverse_iterator ri = // make ri point to the 3 375 | find(v.rbegin(), v.rend(), 3); 376 | vector::iterator i(ri.base());// it points to 4 377 | ``` 378 | 379 | 1) For insertion : using reverse_iterator we insert using ri.base(). 380 | ``` 381 | |------------------------- 382 | | 1 | 2 | 3 | 99 | 4 | 5 | 383 | |------------------------- 384 | ``` 385 | Example : Insert 99 at position of 3 from right to left. 386 | `ri.begin would do the trick.` 387 | 388 | 2) For deletion : Delete the element pointed by ri. 389 | `v.erase(++ri).base()); // erase the element pointed to by ri; this should always compile.` 390 | 391 | --------------------------------------------------------------- 392 | 393 | ### Item 29 : TODO 394 | 395 | --------------------------------------------------------------- 396 | 397 | ### ALGORITHMS 398 | 399 | ### Item 30. Make sure destination ranges are big enough. 400 | 401 | Transform: 402 | ``` 403 | vector results; // apply transmogrify to 404 | transform(values.begin(), values.end(), //each object in values, 405 | back_inserter(results), //inserting the return 406 | transmogrify); 407 | ``` 408 | Use reserve to save time in allocation using: 409 | `results.reserve(results.size() + values.size());` 410 | 411 | Then use back_inserter, front_inserter , inserter. 412 | 413 | If enough space is there in result and you want to overwrite result than you can use: 414 | ``` 415 | transform(values.begin(), values.end(), // overwrite the first 416 | results.begin(), // values.size() elements of 417 | transmogrify); 418 | ``` 419 | 420 | ----------------------------------------------------------------- 421 | 422 | ### Item 31. Know your sorting options. 423 | 424 | 1) `partial_sort` : (Not stable) 425 | Rearranges the elements in the range [first,last), in such a way that the 426 | elements before middle are the smallest elements in the entire range and 427 | are sorted in ascending order, while the remaining elements are left 428 | without any specific order. 429 | `partial_sort (widgets.begin(), widgets.begin() + 20, widgets.end(), qualityCompare);` 430 | // put the best 20 elements (in order) at the front of widgets... 431 | If all you care about is that the 20 best but don't care order of 20 element than use nth_element. 432 | 433 | 2) `nth_element` : (similar to partition algo) (Not Stable) 434 | nth_element is a partial sorting algorithm that rearranges elements in [first, last) such that: 435 | The element pointed at by nth is changed to whatever element would occur in that position if [first, last) was sorted. 436 | All of the elements before this new nth element are less than or equal to the elements after the new nth element. 437 | `nth_element (widgets.begin(), widgets.begin() + 20, widgets.end(), qualityCompare);` 438 | // put the best 20 elements at the front of widgets, but don't worry about their order. 439 | 440 | 3) For stable sorting use `stable_sort` 441 | 442 | 4) `partition` and `stable_partition` 443 | Partition range in two 444 | Rearranges the elements from the range [first,last), in such a way that all the elements 445 | for which pred returns true precede all those for which it returns false. The iterator 446 | returned points to the first element of the second group. 447 | `vector::iterator goodEnd = partition(widgets.begin(), widgets.end(), hasAcceptableQuality);` 448 | // move all widgets satisfying hasAcceptableQuality to the front of widgets, 449 | // and return an iterator to the first widget that isn't satisfactory. 450 | 451 | ------------------------------------------------------------------ 452 | 453 | ### Item 32. Follow remove-like algorithms by erase if you really want to remove something. 454 | 455 | -------------------------------------------------------------------------------- /thread.md: -------------------------------------------------------------------------------- 1 | 2 | ## std::thread 3 | first parameter is name of function to call, and rest of the parameters are arguments to the function. 4 | 5 | std::thread t1(func, std::ref(s)); 6 | 7 | #### Parameter passing 8 | - All parameters are pass by value 9 | - Use `std::ref` to pass by reference. 10 | - function can be passed as function pointer, functors and lambda function. 11 | - We can pass function as a `ref` in case of use with `functors` object. 12 | - `thread t1(std::ref(*functor), arg1, arg2);` 13 | - `std::thread` starts thread as soon as it created. 14 | 15 | #### Methods 16 | - t1.`join()` main process wait for the thread to complete. 17 | - t1.`detach()` → it will freely on its own. You cannot join detached 18 | thread. 19 | - t2.`joinable()` it will tell whether thread is joinable or not. 20 | 21 | #### thread using lambda 22 | ```cpp 23 | int step =10; 24 | vector partial_sum(5, 0); 25 | vector threads; 26 | for(int i =0 ; i < 5 ; i++) { 27 | threads.push_back([&partial_sum, int i, int step]() { 28 | for (int j = i * step ; j < (i+1) * step ; j++) { 29 | partial_sum[i] += j; 30 | } 31 | }); 32 | } 33 | for(std::thread &th : threads) { 34 | if (th.joinable()) { 35 | th.join(); 36 | } 37 | } 38 | int result = std::accumulate(partial_sum.begin(), partial_sum.end(), 0); 39 | 40 | ``` 41 | ### stt::async 42 | - **Alternative** to `thread`, using this `class` we can capture return value of function using `future` 43 | - Future : return value from `std::async` by calling `get()` function. it blocks main thread it future is not ready in similar manner to `join()` 44 | 45 | ```cpp 46 | #include 47 | #include 48 | #include 49 | #include 50 | using namespace std; 51 | 52 | int main() { 53 | 54 | vector > tasks; 55 | int step = 10; 56 | for (int i =0 ; i < 5; i ++) { 57 | tasks.push_back(std::async([i , step]{ 58 | int sum =0; 59 | for(int j = i*step ;j < (i+1)* step; j++) { 60 | sum += j; 61 | } 62 | return sum; 63 | })); 64 | } 65 | 66 | int result =0; 67 | for(auto& t : tasks) { 68 | result+= t.get(); 69 | } 70 | cout < guard(g_mutex); 110 | g_counter++; 111 | ``` 112 | #### unique_lock 113 | lock_guard + lock/unlock feature. 114 | ```cpp 115 | std::unique_lock guard(g_mutex); 116 | g_counter++; 117 | ``` 118 | #### shared_lock 119 | 120 | - It requires to have `std::shared_mutex` instead of `std::mutex` 121 | - It allows multiple threads to have reading access if no write is 122 | happening in another thread. 123 | - If thread is in writing critical section then it will not even allow reading thread. 124 | 125 | #### Deadlock 126 | 127 | ```cpp 128 | print1(string &s, int i) { 129 | std::lock_guard guard1(mu1); 130 | std::lock_guard guard2(mu2); 131 | } 132 | 133 | print2(string &s, int i) { 134 | std::lock_guard guard2(mu2); 135 | std::lock_guard guard1(mu1); 136 | } 137 | 138 | ``` 139 | 140 | #### How to solve this deadlock 141 | 142 | std::lock to lock more then one mutex simultaneously 143 | 144 | #### multiple lock mechanism (`std::lock`) 145 | ```cpp 146 | void Incrementer_Better() { 147 | for (size_t i = 0; i < 100; i++) { 148 | // lock both mutexes without deadlock 149 | std::lock(g_mutex1, g_mutex2); 150 | // make sure both already-locked mutexes are unlocked at the end of scope 151 | std::lock_guard lock1(g_mutex1, std::adopt_lock); 152 | std::lock_guard lock2(g_mutex2, std::adopt_lock); 153 | g_counter++; 154 | } 155 | } 156 | ``` 157 | #### `std::scoped_lock` : c++17 syntax with RAII 158 | `std::scoped_lock scoped_lock_name(g_mutex1, g_mutex2);` 159 | 160 | 161 | #### Fine Grained Locking system 162 | 163 | - std::unique_lock locker(mu); 164 | 165 | - it provide flexibility to lock it and unlock it. 166 | 167 | - std::unique_lock locker(mu, std::defer); // do not lock mutex mu 168 | 169 | - `lock_guard` does not provide this flexiblity. 170 | 171 | - `unique_lock` can be moved from one lock to another: 172 | 173 | `std::unique_lock locker2 = sd::move(locker);` 174 | 175 | #### Lazy initialization : 176 | 177 | ```cpp 178 | std::once_flag _flag; 179 | std::call_once (_flag, & { f.open(”a.txt”)}; 180 | ``` 181 | 182 | ## Conditional Variable 183 | `std::condition_variable g_cv;` 184 | - Protect conditional variable using mutex. 185 | - Always use predicate. 186 | 187 | ### Usage 188 | We use conditional variable for thread communication and message passing. 189 | 190 | --- 191 | `wait` does two things : 192 | - if mutex is locked then it unblocks it so that other thread can continue with their work. 193 | - if mutex is unlocked then it blocks it so that this current thread proceed with its work. 194 | 195 | Important point to note in below producer - consumer program is that condition or `wait` is protected by `unique_lock` and `notify_one` is not under critical section. 196 | 197 | 198 | ```cpp 199 | std::mutex g_mutex; 200 | std::condition_variable g_cv; 201 | bool g_ready = false; 202 | int g_data = 0; 203 | void ConsumeData(int& data) {} 204 | void Consumer() { 205 | int data = 0; 206 | for (int i = 0; i < 100; i++) { 207 | std::unique_lock ul(g_mutex); 208 | //! critical section starts 209 | // if blocked, ul.unlock() is automatically called. 210 | // if unblocked, ul.lock() is automatically called. 211 | g_cv.wait(ul, []() { return g_ready; }); 212 | // Sample data 213 | data = g_data; 214 | std::cout << "data: " << data << std::endl; 215 | g_ready = false; 216 | ul.unlock(); 217 | //critical section end 218 | g_cv.notify_one(); 219 | ConsumeData(data); 220 | } 221 | } 222 | 223 | void Producer() { 224 | for (int i = 0; i < 100; i++) { 225 | std::unique_lock ul(g_mutex); 226 | // Produce data 227 | // critical section starts 228 | g_data = GenRandomValue(); 229 | std::this_thread::sleep_for(std::chrono::milliseconds(100)); 230 | g_ready = true; 231 | ul.unlock(); 232 | // critical section end here. 233 | g_cv.notify_one(); 234 | ul.lock(); 235 | //critical section starts ans wait is inside critical section. 236 | g_cv.wait(ul, []() { return g_ready == false; }); 237 | } 238 | } 239 | 240 | int main() { 241 | std::thread t1(Consumer); 242 | std::thread t2(Producer); 243 | t1.join(); 244 | t2.join(); 245 | return 0; 246 | } 247 | ``` 248 | 249 | ## std::atomic 250 | `std::atomic x(0);` 251 | it ensures read, increment and write atomically. 252 | 253 | #### What type are allowed 254 | - integral types such as `int` `unsigned` , `bool` floating types, 255 | - `float`, `U*`(pointer) and `std::shared_ptr` 256 | 257 | #### User Defined Atomic: 258 | user defined types can be atomic but these classes should be trivially copyable. 259 | 260 | ##### It should satisfy following conditions : 261 | 262 | - continous block of memory so that it can be copy using memcpy 263 | - no user defiend copy, assignment and move constructor 264 | - no virtual function or virtual base class. 265 | 266 | `auto is_trivialy = std::is_trivially_copyable::value;` 267 | 268 | `std::atmoic` is not copy assignable. one atomic variable cannot be assigned to another atomic variable. 269 | ### memeber function of atomic 270 | #### operator= 271 | ```cpp 272 | std::atmoic a(10); 273 | int b; 274 | b = a; 275 | a = b; 276 | ``` 277 | #### store & load 278 | ```cpp 279 | std::atomic a(10); 280 | int b; 281 | b = a.load(); //equivalent to operator= 282 | a.store(b); 283 | ``` 284 | 285 | #### exchange 286 | `old_value = atomic_x.exchange(new_value)` 287 | equivalent to 288 | ``` 289 | vzold_value = atomic_x; 290 | atomic_x = new_value; 291 | ``` 292 | 293 | #### compare_exchange_strong 294 | `bool success = atomic_x.compare_exchange_strong(expected, desired);` 295 | equivalent to 296 | ```cpp 297 | //Atomically do this: 298 | if (atomic_x == expected) { 299 | atomic_x = desired; 300 | return true; 301 | } 302 | else { 303 | expected = atomic_x; 304 | return false; 305 | } 306 | ``` 307 | #### Why do we need compare_exchange? 308 | Lets say if we want to calculate : 309 | `atomix_x = f(atomic_x)` 310 | 311 | while calulating f(x), we check if someone else change value of x, so use new value of x and recalculate f(x) like below : 312 | ```cpp 313 | auto old_x = atomic_x.load(); 314 | while(!atomic_x.compare_exchange_strong(old_x, f(old_x)); 315 | ``` 316 | compare_exchange_weak, similar to `compare_exchange_strong` only difference is that there may be spurious success in case of `weak`. 317 | 318 | ### specialize memeber function 319 | 320 | memory_order_seq_cst 321 | A sql_cst store synchronize with a sql_cst load on same variable. 322 | it keeps total order on the threads. 323 | It provides synchronization and total order. 324 | --------------------------------------------------------------------------------