CPlusPlusNotesForProfessionals PDF
CPlusPlusNotesForProfessionals PDF
C++
Notes for Professionals
600+ pages
of professional hints and tricks
Disclaimer
GoalKicker.com This is an unocial free book created for educational purposes and is
not aliated with ocial C++ group(s) or company(s).
Free Programming Books All trademarks and registered trademarks are
the property of their respective owners
Contents
About ................................................................................................................................................................................... 1
Chapter 1: Getting started with C++ .................................................................................................................... 2
Section 1.1: Hello World ................................................................................................................................................. 2
Section 1.2: Comments .................................................................................................................................................. 3
Section 1.3: The standard C++ compilation process .................................................................................................. 5
Section 1.4: Function ...................................................................................................................................................... 5
Section 1.5: Visibility of function prototypes and declarations ................................................................................. 8
Section 1.6: Preprocessor .............................................................................................................................................. 9
Chapter 2: Templates ............................................................................................................................................... 11
Section 2.1: Basic Class Template .............................................................................................................................. 11
Section 2.2: Function Templates ................................................................................................................................ 11
Section 2.3: Variadic template data structures ........................................................................................................ 13
Section 2.4: Argument forwarding ............................................................................................................................ 15
Section 2.5: Partial template specialization .............................................................................................................. 16
Section 2.6: Template Specialization ......................................................................................................................... 18
Section 2.7: Alias template ......................................................................................................................................... 18
Section 2.8: Explicit instantiation ................................................................................................................................ 18
Section 2.9: Non-type template parameter ............................................................................................................. 19
Section 2.10: Declaring non-type template arguments with auto ......................................................................... 20
Section 2.11: Template template parameters ........................................................................................................... 21
Section 2.12: Default template parameter value ..................................................................................................... 22
Chapter 3: Metaprogramming ............................................................................................................................. 23
Section 3.1: Calculating Factorials ............................................................................................................................. 23
Section 3.2: Iterating over a parameter pack .......................................................................................................... 25
Section 3.3: Iterating with std::integer_sequence .................................................................................................... 26
Section 3.4: Tag Dispatching ...................................................................................................................................... 27
Section 3.5: Detect Whether Expression is Valid ...................................................................................................... 27
Section 3.6: If-then-else .............................................................................................................................................. 29
Section 3.7: Manual distinction of types when given any type T ........................................................................... 29
Section 3.8: Calculating power with C++11 (and higher) .......................................................................................... 30
Section 3.9: Generic Min/Max with variable argument count ................................................................................. 31
Chapter 4: Iterators .................................................................................................................................................. 32
Section 4.1: Overview ................................................................................................................................................... 32
Section 4.2: Vector Iterator ........................................................................................................................................ 35
Section 4.3: Map Iterator ............................................................................................................................................ 35
Section 4.4: Reverse Iterators .................................................................................................................................... 36
Section 4.5: Stream Iterators ...................................................................................................................................... 37
Section 4.6: C Iterators (Pointers) .............................................................................................................................. 37
Section 4.7: Write your own generator-backed iterator ......................................................................................... 38
Chapter 5: Returning several values from a function ............................................................................. 40
Section 5.1: Using std::tuple ......................................................................................................................................... 40
Section 5.2: Structured Bindings ................................................................................................................................ 41
Section 5.3: Using struct ............................................................................................................................................. 42
Section 5.4: Using Output Parameters ...................................................................................................................... 43
Section 5.5: Using a Function Object Consumer ...................................................................................................... 44
Section 5.6: Using std::pair .......................................................................................................................................... 45
Section 5.7: Using std::array ....................................................................................................................................... 45
Section 5.8: Using Output Iterator ............................................................................................................................. 45
Section 5.9: Using std::vector ..................................................................................................................................... 46
Chapter 6: std::string ................................................................................................................................................ 47
Section 6.1: Tokenize ................................................................................................................................................... 47
Section 6.2: Conversion to (const) char* ................................................................................................................... 48
Section 6.3: Using the std::string_view class ............................................................................................................ 48
Section 6.4: Conversion to std::wstring ...................................................................................................................... 49
Section 6.5: Lexicographical comparison ................................................................................................................. 50
Section 6.6: Trimming characters at start/end ........................................................................................................ 51
Section 6.7: String replacement ................................................................................................................................. 53
Section 6.8: Converting to std::string ......................................................................................................................... 54
Section 6.9: Splitting .................................................................................................................................................... 54
Section 6.10: Accessing a character .......................................................................................................................... 55
Section 6.11: Checking if a string is a prefix of another ........................................................................................... 55
Section 6.12: Looping through each character ......................................................................................................... 56
Section 6.13: Conversion to integers/floating point types ...................................................................................... 56
Section 6.14: Concatenation ....................................................................................................................................... 57
Section 6.15: Converting between character encodings ......................................................................................... 58
Section 6.16: Finding character(s) in a string ............................................................................................................ 59
Chapter 7: Namespaces .......................................................................................................................................... 60
Section 7.1: What are namespaces? .......................................................................................................................... 60
Section 7.2: Argument Dependent Lookup ............................................................................................................... 61
Section 7.3: Extending namespaces .......................................................................................................................... 62
Section 7.4: Using directive ......................................................................................................................................... 62
Section 7.5: Making namespaces .............................................................................................................................. 63
Section 7.6: Unnamed/anonymous namespaces ................................................................................................... 64
Section 7.7: Compact nested namespaces ............................................................................................................... 64
Section 7.8: Namespace alias .................................................................................................................................... 64
Section 7.9: Inline namespace .................................................................................................................................... 65
Section 7.10: Aliasing a long namespace .................................................................................................................. 67
Section 7.11: Alias Declaration scope ......................................................................................................................... 67
Chapter 8: File I/O ...................................................................................................................................................... 69
Section 8.1: Writing to a file ........................................................................................................................................ 69
Section 8.2: Opening a file .......................................................................................................................................... 69
Section 8.3: Reading from a file ................................................................................................................................. 70
Section 8.4: Opening modes ...................................................................................................................................... 72
Section 8.5: Reading an ASCII file into a std::string .................................................................................................. 73
Section 8.6: Writing files with non-standard locale settings ................................................................................... 74
Section 8.7: Checking end of file inside a loop condition, bad practice? ............................................................... 75
Section 8.8: Flushing a stream ................................................................................................................................... 76
Section 8.9: Reading a file into a container .............................................................................................................. 76
Section 8.10: Copying a file ......................................................................................................................................... 77
Section 8.11: Closing a file ........................................................................................................................................... 77
Section 8.12: Reading a `struct` from a formatted text file ..................................................................................... 78
Chapter 9: Classes/Structures ............................................................................................................................. 80
Section 9.1: Class basics .............................................................................................................................................. 80
Section 9.2: Final classes and structs ........................................................................................................................ 80
Section 9.3: Access specifiers ..................................................................................................................................... 81
Section 9.4: Inheritance ............................................................................................................................................... 82
Section 9.5: Friendship ................................................................................................................................................ 84
Section 9.6: Virtual Inheritance .................................................................................................................................. 85
Section 9.7: Private inheritance: restricting base class interface ........................................................................... 86
Section 9.8: Accessing class members ..................................................................................................................... 87
Section 9.9: Member Types and Aliases ................................................................................................................... 88
Section 9.10: Nested Classes/Structures ................................................................................................................... 91
Section 9.11: Unnamed struct/class ........................................................................................................................... 96
Section 9.12: Static class members ............................................................................................................................ 97
Section 9.13: Multiple Inheritance ............................................................................................................................. 101
Section 9.14: Non-static member functions ............................................................................................................ 102
Chapter 10: Smart Pointers ................................................................................................................................. 105
Section 10.1: Unique ownership (std::unique_ptr) ................................................................................................... 105
Section 10.2: Sharing ownership (std::shared_ptr) ................................................................................................ 106
Section 10.3: Sharing with temporary ownership (std::weak_ptr) ........................................................................ 108
Section 10.4: Using custom deleters to create a wrapper to a C interface ......................................................... 110
Section 10.5: Unique ownership without move semantics (auto_ptr) ................................................................. 111
Section 10.6: Casting std::shared_ptr pointers ....................................................................................................... 113
Section 10.7: Writing a smart pointer: value_ptr .................................................................................................... 113
Section 10.8: Getting a shared_ptr referring to this .............................................................................................. 115
Chapter 11: Function Overloading .................................................................................................................... 117
Section 11.1: What is Function Overloading? ........................................................................................................... 117
Section 11.2: Return Type in Function Overloading ................................................................................................ 118
Section 11.3: Member Function cv-qualifier Overloading ...................................................................................... 118
Chapter 12: std::vector ........................................................................................................................................... 121
Section 12.1: Accessing Elements ............................................................................................................................. 121
Section 12.2: Initializing a std::vector ....................................................................................................................... 123
Section 12.3: Deleting Elements ............................................................................................................................... 124
Section 12.4: Iterating Over std::vector .................................................................................................................... 126
Section 12.5: vector<bool>: The Exception To So Many, So Many Rules ............................................................. 128
Section 12.6: Inserting Elements ............................................................................................................................... 130
Section 12.7: Using std::vector as a C array ............................................................................................................ 131
Section 12.8: Finding an Element in std::vector ...................................................................................................... 131
Section 12.9: Concatenating Vectors ....................................................................................................................... 132
Section 12.10: Matrices Using Vectors ..................................................................................................................... 133
Section 12.11: Using a Sorted Vector for Fast Element Lookup ............................................................................. 134
Section 12.12: Reducing the Capacity of a Vector .................................................................................................. 135
Section 12.13: Vector size and capacity ................................................................................................................... 135
Section 12.14: Iterator/Pointer Invalidation ............................................................................................................. 137
Section 12.15: Find max and min Element and Respective Index in a Vector ..................................................... 138
Section 12.16: Converting an array to std::vector ................................................................................................... 138
Section 12.17: Functions Returning Large Vectors ................................................................................................. 139
Chapter 13: Operator Overloading .................................................................................................................. 141
Section 13.1: Arithmetic operators ............................................................................................................................ 141
Section 13.2: Array subscript operator .................................................................................................................... 142
Section 13.3: Conversion operators ......................................................................................................................... 143
Section 13.4: Complex Numbers Revisited .............................................................................................................. 144
Section 13.5: Named operators ................................................................................................................................ 148
Section 13.6: Unary operators .................................................................................................................................. 150
Section 13.7: Comparison operators ........................................................................................................................ 151
Section 13.8: Assignment operator .......................................................................................................................... 152
Section 13.9: Function call operator ......................................................................................................................... 153
Section 13.10: Bitwise NOT operator ........................................................................................................................ 153
Section 13.11: Bit shift operators for I/O .................................................................................................................. 154
Chapter 14: Lambdas ............................................................................................................................................. 155
Section 14.1: What is a lambda expression? ........................................................................................................... 155
Section 14.2: Specifying the return type .................................................................................................................. 157
Section 14.3: Capture by value ................................................................................................................................. 158
Section 14.4: Recursive lambdas .............................................................................................................................. 159
Section 14.5: Default capture ................................................................................................................................... 161
Section 14.6: Class lambdas and capture of this .................................................................................................... 161
Section 14.7: Capture by reference .......................................................................................................................... 163
Section 14.8: Generic lambdas ................................................................................................................................. 163
Section 14.9: Using lambdas for inline parameter pack unpacking .................................................................... 164
Section 14.10: Generalized capture .......................................................................................................................... 166
Section 14.11: Conversion to function pointer .......................................................................................................... 167
Section 14.12: Porting lambda functions to C++03 using functors ....................................................................... 167
Chapter 15: Loops ..................................................................................................................................................... 169
Section 15.1: Range-Based For ................................................................................................................................. 169
Section 15.2: For loop ................................................................................................................................................ 171
Section 15.3: While loop ............................................................................................................................................ 173
Section 15.4: Do-while loop ....................................................................................................................................... 174
Section 15.5: Loop Control statements : Break and Continue ............................................................................... 175
Section 15.6: Declaration of variables in conditions .............................................................................................. 176
Section 15.7: Range-for over a sub-range .............................................................................................................. 177
Chapter 16: std::map ............................................................................................................................................... 179
Section 16.1: Accessing elements ............................................................................................................................. 179
Section 16.2: Inserting elements ............................................................................................................................... 180
Section 16.3: Searching in std::map or in std::multimap ......................................................................................... 181
Section 16.4: Initializing a std::map or std::multimap .............................................................................................. 182
Section 16.5: Checking number of elements ........................................................................................................... 183
Section 16.6: Types of Maps ..................................................................................................................................... 183
Section 16.7: Deleting elements ................................................................................................................................ 184
Section 16.8: Iterating over std::map or std::multimap ........................................................................................... 185
Section 16.9: Creating std::map with user-defined types as key .......................................................................... 185
Chapter 17: Threading ............................................................................................................................................ 187
Section 17.1: Creating a std::thread .......................................................................................................................... 187
Section 17.2: Passing a reference to a thread ........................................................................................................ 189
Section 17.3: Using std::async instead of std::thread .............................................................................................. 189
Section 17.4: Basic Synchronization ......................................................................................................................... 190
Section 17.5: Create a simple thread pool .............................................................................................................. 190
Section 17.6: Ensuring a thread is always joined .................................................................................................... 192
Section 17.7: Operations on the current thread ...................................................................................................... 193
Section 17.8: Using Condition Variables .................................................................................................................. 194
Section 17.9: Thread operations ............................................................................................................................... 196
Section 17.10: Thread-local storage ......................................................................................................................... 196
Section 17.11: Reassigning thread objects ............................................................................................................... 197
Chapter 18: Value Categories ............................................................................................................................. 198
Section 18.1: Value Category Meanings .................................................................................................................. 198
Section 18.2: rvalue .................................................................................................................................................... 198
Section 18.3: xvalue ................................................................................................................................................... 199
Section 18.4: prvalue ................................................................................................................................................. 199
Section 18.5: lvalue .................................................................................................................................................... 200
Section 18.6: glvalue .................................................................................................................................................. 200
Chapter 19: Preprocessor ..................................................................................................................................... 201
Section 19.1: Include Guards ..................................................................................................................................... 201
Section 19.2: Conditional logic and cross-platform handling ............................................................................... 202
Section 19.3: X-macros .............................................................................................................................................. 203
Section 19.4: Macros .................................................................................................................................................. 205
Section 19.5: Predefined macros .............................................................................................................................. 208
Section 19.6: Preprocessor Operators ..................................................................................................................... 210
Section 19.7: #pragma once ..................................................................................................................................... 210
Section 19.8: Preprocessor error messages ........................................................................................................... 211
Chapter 20: SFINAE (Substitution Failure Is Not An Error) .................................................................. 212
Section 20.1: What is SFINAE .................................................................................................................................... 212
Section 20.2: void_t .................................................................................................................................................. 212
Section 20.3: enable_if ............................................................................................................................................. 214
Section 20.4: is_detected ......................................................................................................................................... 215
Section 20.5: Overload resolution with a large number of options ..................................................................... 217
Section 20.6: trailing decltype in function templates ............................................................................................ 218
Section 20.7: enable_if_all / enable_if_any ......................................................................................................... 219
Chapter 21: The Rule of Three, Five, And Zero .......................................................................................... 221
Section 21.1: Rule of Zero .......................................................................................................................................... 221
Section 21.2: Rule of Five .......................................................................................................................................... 222
Section 21.3: Rule of Three ....................................................................................................................................... 223
Section 21.4: Self-assignment Protection ................................................................................................................ 224
Chapter 22: RAII: Resource Acquisition Is Initialization ......................................................................... 226
Section 22.1: Locking ................................................................................................................................................. 226
Section 22.2: ScopeSuccess (c++17) ........................................................................................................................ 227
Section 22.3: ScopeFail (c++17) ................................................................................................................................ 228
Section 22.4: Finally/ScopeExit ................................................................................................................................ 229
Chapter 23: Exceptions .......................................................................................................................................... 230
Section 23.1: Catching exceptions ............................................................................................................................ 230
Section 23.2: Rethrow (propagate) exception ....................................................................................................... 231
Section 23.3: Best practice: throw by value, catch by const reference ............................................................... 232
Section 23.4: Custom exception ............................................................................................................................... 233
Section 23.5: std::uncaught_exceptions .................................................................................................................. 235
Section 23.6: Function Try Block for regular function ........................................................................................... 236
Section 23.7: Nested exception ................................................................................................................................ 236
Section 23.8: Function Try Blocks In constructor ................................................................................................... 238
Section 23.9: Function Try Blocks In destructor ..................................................................................................... 239
Chapter 24: Implementation-defined behavior ....................................................................................... 240
Section 24.1: Size of integral types .......................................................................................................................... 240
Section 24.2: Char might be unsigned or signed ................................................................................................... 242
Section 24.3: Ranges of numeric types .................................................................................................................. 242
Section 24.4: Value representation of floating point types .................................................................................. 243
Section 24.5: Overflow when converting from integer to signed integer ........................................................... 243
Section 24.6: Underlying type (and hence size) of an enum ................................................................................ 244
Section 24.7: Numeric value of a pointer ................................................................................................................ 244
Section 24.8: Number of bits in a byte .................................................................................................................... 245
Chapter 25: Special Member Functions ......................................................................................................... 246
Section 25.1: Default Constructor ............................................................................................................................ 246
Section 25.2: Destructor ........................................................................................................................................... 248
Section 25.3: Copy and swap ................................................................................................................................... 249
Section 25.4: Implicit Move and Copy ..................................................................................................................... 251
Chapter 26: Random number generation .................................................................................................... 252
Section 26.1: True random value generator ........................................................................................................... 252
Section 26.2: Generating a pseudo-random number ........................................................................................... 252
Section 26.3: Using the generator for multiple distributions ................................................................................ 253
Chapter 27: References ......................................................................................................................................... 254
Section 27.1: Defining a reference ........................................................................................................................... 254
Chapter 28: Sorting ................................................................................................................................................. 255
Section 28.1: Sorting and sequence containers ...................................................................................................... 255
Section 28.2: sorting with std::map (ascending and descending) ....................................................................... 255
Section 28.3: Sorting sequence containers by overloaded less operator ........................................................... 257
Section 28.4: Sorting sequence containers using compare function .................................................................. 258
Section 28.5: Sorting sequence containers using lambda expressions (C++11) .................................................. 259
Section 28.6: Sorting built-in arrays ........................................................................................................................ 260
Section 28.7: Sorting sequence containers with specifed ordering ..................................................................... 260
Chapter 29: Regular expressions ...................................................................................................................... 261
Section 29.1: Basic regex_match and regex_search Examples ........................................................................... 261
Section 29.2: regex_iterator Example ..................................................................................................................... 261
Section 29.3: Anchors ................................................................................................................................................ 262
Section 29.4: regex_replace Example .................................................................................................................... 263
Section 29.5: regex_token_iterator Example ........................................................................................................ 263
Section 29.6: Quantifiers ........................................................................................................................................... 263
Section 29.7: Splitting a string .................................................................................................................................. 265
Chapter 30: Polymorphism .................................................................................................................................. 266
Section 30.1: Define polymorphic classes ............................................................................................................... 266
Section 30.2: Safe downcasting ............................................................................................................................... 267
Section 30.3: Polymorphism & Destructors ............................................................................................................ 268
Chapter 31: Perfect Forwarding ........................................................................................................................ 270
Section 31.1: Factory functions ................................................................................................................................. 270
Chapter 32: Virtual Member Functions .......................................................................................................... 271
Section 32.1: Final virtual functions .......................................................................................................................... 271
Section 32.2: Using override with virtual in C++11 and later .................................................................................. 271
Section 32.3: Virtual vs non-virtual member functions ......................................................................................... 272
Section 32.4: Behaviour of virtual functions in constructors and destructors .................................................... 273
Section 32.5: Pure virtual functions ......................................................................................................................... 274
Chapter 33: Undefined Behavior ....................................................................................................................... 277
Section 33.1: Reading or writing through a null pointer ......................................................................................... 277
Section 33.2: Using an uninitialized local variable ................................................................................................. 277
Section 33.3: Accessing an out-of-bounds index ................................................................................................... 278
Section 33.4: Deleting a derived object via a pointer to a base class that doesn't have a virtual destructor
............................................................................................................................................................................. 278
Section 33.5: Extending the `std` or `posix` Namespace ........................................................................................ 278
Section 33.6: Invalid pointer arithmetic ................................................................................................................... 279
Section 33.7: No return statement for a function with a non-void return type .................................................. 280
Section 33.8: Accessing a dangling reference ....................................................................................................... 280
Section 33.9: Integer division by zero ...................................................................................................................... 281
Section 33.10: Shifting by an invalid number of positions ..................................................................................... 281
Section 33.11: Incorrect pairing of memory allocation and deallocation ............................................................. 281
Section 33.12: Signed Integer Overflow ................................................................................................................... 282
Section 33.13: Multiple non-identical definitions (the One Definition Rule) .......................................................... 282
Section 33.14: Modifying a const object .................................................................................................................. 283
Section 33.15: Returning from a [[noreturn]] function .......................................................................................... 284
Section 33.16: Infinite template recursion ................................................................................................................ 284
Section 33.17: Overflow during conversion to or from floating point type ......................................................... 285
Section 33.18: Modifying a string literal ................................................................................................................... 285
Section 33.19: Accessing an object as the wrong type .......................................................................................... 285
Section 33.20: Invalid derived-to-base conversion for pointers to members .................................................... 286
Section 33.21: Destroying an object that has already been destroyed ............................................................... 286
Section 33.22: Access to nonexistent member through pointer to member ...................................................... 287
Section 33.23: Invalid base-to-derived static cast ................................................................................................. 287
Section 33.24: Floating point overflow .................................................................................................................... 287
Section 33.25: Calling (Pure) Virtual Members From Constructor Or Destructor .............................................. 287
Section 33.26: Function call through mismatched function pointer type ............................................................ 288
Chapter 34: Value and Reference Semantics ........................................................................................... 289
Section 34.1: Definitions ............................................................................................................................................ 289
Section 34.2: Deep copying and move support ..................................................................................................... 289
Chapter 35: Overload resolution ...................................................................................................................... 293
Section 35.1: Categorization of argument to parameter cost .............................................................................. 293
Section 35.2: Arithmetic promotions and conversions .......................................................................................... 293
Section 35.3: Overloading on Forwarding Reference ........................................................................................... 294
Section 35.4: Exact match ........................................................................................................................................ 295
Section 35.5: Overloading on constness and volatility .......................................................................................... 295
Section 35.6: Name lookup and access checking .................................................................................................. 296
Section 35.7: Overloading within a class hierarchy ............................................................................................... 297
Section 35.8: Steps of Overload Resolution ........................................................................................................... 298
Chapter 36: Move Semantics .............................................................................................................................. 300
Section 36.1: Move semantics ................................................................................................................................... 300
Section 36.2: Using std::move to reduce complexity from O(n²) to O(n) ............................................................ 300
Section 36.3: Move constructor ................................................................................................................................ 303
Section 36.4: Re-use a moved object ...................................................................................................................... 305
Section 36.5: Move assignment ............................................................................................................................... 305
Section 36.6: Using move semantics on containers .............................................................................................. 306
Chapter 37: Pointers to members .................................................................................................................... 308
Section 37.1: Pointers to static member functions ................................................................................................. 308
Section 37.2: Pointers to member functions ........................................................................................................... 308
Section 37.3: Pointers to member variables ........................................................................................................... 309
Section 37.4: Pointers to static member variables ................................................................................................ 309
Chapter 38: Pimpl Idiom ........................................................................................................................................ 311
Section 38.1: Basic Pimpl idiom ................................................................................................................................ 311
Chapter 39: std::function: To wrap any element that is callable .................................................... 313
Section 39.1: Simple usage ....................................................................................................................................... 313
Section 39.2: std::function used with std::bind ........................................................................................................ 313
Section 39.3: Binding std::function to a dierent callable types .......................................................................... 314
Section 39.4: Storing function arguments in std::tuple .......................................................................................... 316
Section 39.5: std::function with lambda and std::bind ............................................................................................ 317
Section 39.6: `function` overhead ............................................................................................................................. 318
Chapter 40: const keyword ................................................................................................................................ 319
Section 40.1: Avoiding duplication of code in const and non-const getter methods ......................................... 319
Section 40.2: Const member functions ................................................................................................................... 320
Section 40.3: Const local variables .......................................................................................................................... 321
Section 40.4: Const pointers ..................................................................................................................................... 321
Chapter 41: auto ....................................................................................................................................................... 323
Section 41.1: Basic auto sample ............................................................................................................................... 323
Section 41.2: Generic lambda (C++14) ..................................................................................................................... 323
Section 41.3: auto and proxy objects ....................................................................................................................... 324
Section 41.4: auto and Expression Templates ........................................................................................................ 324
Section 41.5: auto, const, and references ................................................................................................................ 325
Section 41.6: Trailing return type ............................................................................................................................. 325
Chapter 42: std::optional ..................................................................................................................................... 327
Section 42.1: Using optionals to represent the absence of a value ..................................................................... 327
Section 42.2: optional as return value .................................................................................................................... 327
Section 42.3: value_or .............................................................................................................................................. 328
Section 42.4: Introduction ......................................................................................................................................... 328
Section 42.5: Using optionals to represent the failure of a function ................................................................... 329
Chapter 43: Copy Elision ....................................................................................................................................... 331
Section 43.1: Purpose of copy elision ...................................................................................................................... 331
Section 43.2: Guaranteed copy elision .................................................................................................................... 332
Section 43.3: Parameter elision ................................................................................................................................ 333
Section 43.4: Return value elision ............................................................................................................................ 333
Section 43.5: Named return value elision ............................................................................................................... 333
Section 43.6: Copy initialization elision .................................................................................................................... 334
Chapter 44: Bit Operators .................................................................................................................................. 335
Section 44.1: | - bitwise OR ........................................................................................................................................ 335
Section 44.2: ^ - bitwise XOR (exclusive OR) .......................................................................................................... 335
Section 44.3: & - bitwise AND ................................................................................................................................... 337
Section 44.4: << - left shift ........................................................................................................................................ 337
Section 44.5: >> - right shift ...................................................................................................................................... 338
Chapter 45: Fold Expressions ............................................................................................................................. 340
Section 45.1: Unary Folds .......................................................................................................................................... 340
Section 45.2: Binary Folds ........................................................................................................................................ 340
Section 45.3: Folding over a comma ....................................................................................................................... 341
Chapter 46: Unions .................................................................................................................................................. 342
Section 46.1: Undefined Behavior ............................................................................................................................ 342
Section 46.2: Basic Union Features ......................................................................................................................... 342
Section 46.3: Typical Use .......................................................................................................................................... 342
Chapter 47: Unnamed types .............................................................................................................................. 344
Section 47.1: Unnamed classes ................................................................................................................................ 344
Section 47.2: As a type alias .................................................................................................................................... 344
Section 47.3: Anonymous members ........................................................................................................................ 344
Section 47.4: Anonymous Union .............................................................................................................................. 345
Chapter 48: mutable keyword .......................................................................................................................... 346
Section 48.1: mutable lambdas ................................................................................................................................ 346
Section 48.2: non-static class member modifier ................................................................................................... 346
Chapter 49: Bit fields .............................................................................................................................................. 348
Section 49.1: Declaration and Usage ....................................................................................................................... 348
Chapter 50: std::array ........................................................................................................................................... 349
Section 50.1: Initializing an std::array ....................................................................................................................... 349
Section 50.2: Element access ................................................................................................................................... 350
Section 50.3: Iterating through the Array ............................................................................................................... 352
Section 50.4: Checking size of the Array ................................................................................................................ 352
Section 50.5: Changing all array elements at once .............................................................................................. 352
Chapter 51: Singleton Design Pattern ............................................................................................................ 353
Section 51.1: Lazy Initialization .................................................................................................................................. 353
Section 51.2: Static deinitialization-safe singleton ................................................................................................. 354
Section 51.3: Thread-safe Singeton ......................................................................................................................... 354
Section 51.4: Subclasses ............................................................................................................................................ 354
Chapter 52: The ISO C++ Standard ................................................................................................................. 356
Section 52.1: Current Working Drafts ...................................................................................................................... 356
Section 52.2: C++17 .................................................................................................................................................... 356
Section 52.3: C++11 ..................................................................................................................................................... 357
Section 52.4: C++14 .................................................................................................................................................... 358
Section 52.5: C++98 ................................................................................................................................................... 359
Section 52.6: C++03 ................................................................................................................................................... 359
Section 52.7: C++20 ................................................................................................................................................... 360
Chapter 53: User-Defined Literals ................................................................................................................... 361
Section 53.1: Self-made user-defined literal for binary ......................................................................................... 361
Section 53.2: Standard user-defined literals for duration ..................................................................................... 361
Section 53.3: User-defined literals with long double values ................................................................................. 362
Section 53.4: Standard user-defined literals for strings ........................................................................................ 362
Section 53.5: Standard user-defined literals for complex ..................................................................................... 363
Chapter 54: Enumeration ..................................................................................................................................... 364
Section 54.1: Iteration over an enum ....................................................................................................................... 364
Section 54.2: Scoped enums .................................................................................................................................... 365
Section 54.3: Enum forward declaration in C++11 .................................................................................................. 366
Section 54.4: Basic Enumeration Declaration ........................................................................................................ 366
Section 54.5: Enumeration in switch statements ................................................................................................... 367
Chapter 55: Type Erasure .................................................................................................................................... 368
Section 55.1: A move-only `std::function` ................................................................................................................. 368
Section 55.2: Erasing down to a Regular type with manual vtable ..................................................................... 370
Section 55.3: Basic mechanism ................................................................................................................................ 373
Section 55.4: Erasing down to a contiguous buer of T ....................................................................................... 374
Section 55.5: Type erasing type erasure with std::any .......................................................................................... 375
Chapter 56: Memory management ................................................................................................................. 380
Section 56.1: Free Storage (Heap, Dynamic Allocation ...) ..................................................................................... 380
Section 56.2: Placement new ................................................................................................................................... 381
Section 56.3: Stack .................................................................................................................................................... 382
Chapter 57: Bit Manipulation .............................................................................................................................. 383
Section 57.1: Remove rightmost set bit ................................................................................................................... 383
Section 57.2: Set all bits ............................................................................................................................................ 383
Section 57.3: Toggling a bit ...................................................................................................................................... 383
Section 57.4: Checking a bit ..................................................................................................................................... 383
Section 57.5: Counting bits set ................................................................................................................................. 384
Section 57.6: Check if an integer is a power of 2 ................................................................................................... 385
Section 57.7: Setting a bit ......................................................................................................................................... 385
Section 57.8: Clearing a bit ....................................................................................................................................... 385
Section 57.9: Changing the nth bit to x ................................................................................................................... 385
Section 57.10: Bit Manipulation Application: Small to Capital Letter .................................................................... 386
Chapter 58: Arrays ................................................................................................................................................... 387
Section 58.1: Array initialization ............................................................................................................................... 387
Section 58.2: A fixed size raw array matrix (that is, a 2D raw array) .................................................................. 388
Section 58.3: Dynamically sized raw array ............................................................................................................ 388
Section 58.4: Array size: type safe at compile time ............................................................................................... 389
Section 58.5: Expanding dynamic size array by using std::vector ....................................................................... 390
Section 58.6: A dynamic size matrix using std::vector for storage ...................................................................... 391
Chapter 59: Pointers ............................................................................................................................................... 394
Section 59.1: Pointer Operations .............................................................................................................................. 394
Section 59.2: Pointer basics ...................................................................................................................................... 394
Section 59.3: Pointer Arithmetic ............................................................................................................................... 396
Chapter 60: Explicit type conversions ............................................................................................................ 398
Section 60.1: C-style casting ..................................................................................................................................... 398
Section 60.2: Casting away constness .................................................................................................................... 398
Section 60.3: Base to derived conversion ............................................................................................................... 398
Section 60.4: Conversion between pointer and integer ........................................................................................ 399
Section 60.5: Conversion by explicit constructor or explicit conversion function .............................................. 400
Section 60.6: Implicit conversion ............................................................................................................................. 400
Section 60.7: Enum conversions .............................................................................................................................. 400
Section 60.8: Derived to base conversion for pointers to members ................................................................... 402
Section 60.9: void* to T* ............................................................................................................................................ 402
Section 60.10: Type punning conversion ................................................................................................................ 402
Chapter 61: RTTI: Run-Time Type Information ......................................................................................... 404
Section 61.1: dynamic_cast ....................................................................................................................................... 404
Section 61.2: The typeid keyword ............................................................................................................................ 404
Section 61.3: Name of a type ................................................................................................................................... 405
Section 61.4: When to use which cast in c++ ........................................................................................................... 405
Chapter 62: Standard Library Algorithms ................................................................................................... 406
Section 62.1: std::next_permutation ......................................................................................................................... 406
Section 62.2: std::for_each ....................................................................................................................................... 406
Section 62.3: std::accumulate ................................................................................................................................... 407
Section 62.4: std::find ................................................................................................................................................ 408
Section 62.5: std::min_element ................................................................................................................................ 410
Section 62.6: std::find_if ............................................................................................................................................ 411
Section 62.7: Using std::nth_element To Find The Median (Or Other Quantiles) ............................................... 412
Section 62.8: std::count ............................................................................................................................................. 413
Section 62.9: std::count_if ......................................................................................................................................... 414
Chapter 63: Friend keyword ................................................................................................................................ 416
Section 63.1: Friend function ..................................................................................................................................... 416
Section 63.2: Friend method .................................................................................................................................... 417
Section 63.3: Friend class ......................................................................................................................................... 417
Chapter 64: Expression templates .................................................................................................................. 419
Section 64.1: A basic example illustrating expression templates ......................................................................... 419
Chapter 65: Scopes .................................................................................................................................................. 423
Section 65.1: Global variables ................................................................................................................................... 423
Section 65.2: Simple block scope ............................................................................................................................ 423
Chapter 66: Atomic Types .................................................................................................................................... 425
Section 66.1: Multi-threaded Access ........................................................................................................................ 425
Chapter 67: static_assert .................................................................................................................................... 427
Section 67.1: static_assert ........................................................................................................................................ 427
Chapter 68: operator precedence ................................................................................................................... 428
Section 68.1: Logical && and || operators: short-circuit ......................................................................................... 428
Section 68.2: Unary Operators ................................................................................................................................ 429
Section 68.3: Arithmetic operators .......................................................................................................................... 429
Section 68.4: Logical AND and OR operators ........................................................................................................ 430
Chapter 69: constexpr ............................................................................................................................................ 431
Section 69.1: constexpr variables ............................................................................................................................. 431
Section 69.2: Static if statement .............................................................................................................................. 432
Section 69.3: constexpr functions ............................................................................................................................ 433
Chapter 70: Date and time using <chrono> header ............................................................................... 435
Section 70.1: Measuring time using <chrono> ........................................................................................................ 435
Section 70.2: Find number of days between two dates ........................................................................................ 435
Chapter 71: Trailing return type ....................................................................................................................... 437
Section 71.1: Avoid qualifying a nested type name ................................................................................................ 437
Section 71.2: Lambda expressions ........................................................................................................................... 437
Chapter 72: Function Template Overloading ............................................................................................ 438
Section 72.1: What is a valid function template overloading? .............................................................................. 438
Chapter 73: Common compile/linker errors (GCC) ................................................................................. 439
Section 73.1: undefined reference to `***' ................................................................................................................. 439
Section 73.2: error: '***' was not declared in this scope ......................................................................................... 439
Section 73.3: fatal error: ***: No such file or directory ............................................................................................ 441
Chapter 74: Design pattern implementation in C++ .............................................................................. 442
Section 74.1: Adapter Pattern ................................................................................................................................... 442
Section 74.2: Observer pattern ................................................................................................................................ 444
Section 74.3: Factory Pattern ................................................................................................................................... 447
Section 74.4: Builder Pattern with Fluent API .......................................................................................................... 448
Chapter 75: Optimization in C++ ....................................................................................................................... 451
Section 75.1: Introduction to performance ............................................................................................................. 451
Section 75.2: Empty Base Class Optimization ........................................................................................................ 451
Section 75.3: Optimizing by executing less code ................................................................................................... 452
Section 75.4: Using ecient containers .................................................................................................................. 453
Section 75.5: Small Object Optimization ................................................................................................................. 454
Chapter 76: Compiling and Building ................................................................................................................ 456
Section 76.1: Compiling with GCC ............................................................................................................................. 456
Section 76.2: Compiling with Visual Studio (Graphical Interface) - Hello World ................................................ 457
Section 76.3: Online Compilers ................................................................................................................................. 462
Section 76.4: Compiling with Visual C++ (Command Line) ................................................................................... 464
Section 76.5: Compiling with Clang ......................................................................................................................... 467
Section 76.6: The C++ compilation process ............................................................................................................ 467
Section 76.7: Compiling with Code::Blocks (Graphical interface) ......................................................................... 469
Chapter 77: Type Traits ........................................................................................................................................ 472
Section 77.1: Type Properties ................................................................................................................................... 472
Section 77.2: Standard type traits ........................................................................................................................... 473
Section 77.3: Type relations with std::is_same<T, T> ............................................................................................. 474
Section 77.4: Fundamental type traits .................................................................................................................... 475
Chapter 78: std::pair ............................................................................................................................................... 476
Section 78.1: Compare operators ............................................................................................................................ 476
Section 78.2: Creating a Pair and accessing the elements ................................................................................... 477
Chapter 79: Keywords ............................................................................................................................................ 478
Section 79.1: asm ....................................................................................................................................................... 478
Section 79.2: Dierent keywords ............................................................................................................................. 478
Section 79.3: typename ............................................................................................................................................ 482
Section 79.4: explicit .................................................................................................................................................. 483
Section 79.5: sizeof .................................................................................................................................................... 484
Section 79.6: noexcept .............................................................................................................................................. 484
Chapter 80: One Definition Rule (ODR) ......................................................................................................... 486
Section 80.1: ODR violation via overload resolution .............................................................................................. 486
Section 80.2: Multiply defined function ................................................................................................................... 486
Section 80.3: Inline functions .................................................................................................................................... 487
Chapter 81: Unspecified behavior .................................................................................................................... 489
Section 81.1: Value of an out-of-range enum ......................................................................................................... 489
Section 81.2: Evaluation order of function arguments .......................................................................................... 489
Section 81.3: Result of some reinterpret_cast conversions .................................................................................. 490
Section 81.4: Space occupied by a reference ......................................................................................................... 491
Section 81.5: Moved-from state of most standard library classes ...................................................................... 491
Section 81.6: Result of some pointer comparisons ................................................................................................ 492
Section 81.7: Static cast from bogus void* value .................................................................................................... 492
Section 81.8: Order of initialization of globals across TU ...................................................................................... 492
Chapter 82: Floating Point Arithmetic ........................................................................................................... 494
Section 82.1: Floating Point Numbers are Weird .................................................................................................... 494
Chapter 83: Argument Dependent Name Lookup ................................................................................... 495
Section 83.1: What functions are found .................................................................................................................. 495
Chapter 84: std::variant ....................................................................................................................................... 496
Section 84.1: Create pseudo-method pointers ....................................................................................................... 496
Section 84.2: Basic std::variant use ......................................................................................................................... 497
Section 84.3: Constructing a `std::variant` ............................................................................................................... 498
Chapter 85: Attributes ........................................................................................................................................... 499
Section 85.1: [[fallthrough]] ..................................................................................................................................... 499
Section 85.2: [[nodiscard]] ...................................................................................................................................... 499
Section 85.3: [[deprecated]] and [[deprecated("reason")]] ............................................................................... 500
Section 85.4: [[maybe_unused]] ............................................................................................................................ 500
Section 85.5: [[noreturn]] ......................................................................................................................................... 501
Chapter 86: Profiling ............................................................................................................................................... 503
Section 86.1: Profiling with gcc and gprof ............................................................................................................... 503
Section 86.2: Generating callgraph diagrams with gperf2dot ............................................................................. 503
Section 86.3: Profiling CPU Usage with gcc and Google Perf Tools .................................................................... 504
Chapter 87: Return Type Covariance ............................................................................................................ 506
Section 87.1: Covariant result version of the base example, static type checking ............................................. 506
Section 87.2: Covariant smart pointer result (automated cleanup) .................................................................... 506
Chapter 88: Non-Static Member Functions ................................................................................................. 508
Section 88.1: Non-static Member Functions ........................................................................................................... 508
Section 88.2: Encapsulation ..................................................................................................................................... 509
Section 88.3: Name Hiding & Importing .................................................................................................................. 509
Section 88.4: Virtual Member Functions ................................................................................................................. 511
Section 88.5: Const Correctness .............................................................................................................................. 513
Chapter 89: Recursion in C++ ............................................................................................................................. 515
Section 89.1: Using tail recursion and Fibonnaci-style recursion to solve the Fibonnaci sequence ................. 515
Section 89.2: Recursion with memoization ............................................................................................................. 515
Chapter 90: Callable Objects .............................................................................................................................. 517
Section 90.1: Function Pointers ................................................................................................................................ 517
Section 90.2: Classes with operator() (Functors) .................................................................................................. 517
Chapter 91: std::iomanip ....................................................................................................................................... 519
Section 91.1: std::setprecision .................................................................................................................................... 519
Section 91.2: std::setfill ............................................................................................................................................... 519
Section 91.3: std::setiosflags ..................................................................................................................................... 519
Section 91.4: std::setw ................................................................................................................................................ 521
Chapter 92: Constant class member functions ......................................................................................... 522
Section 92.1: constant member function ................................................................................................................ 522
Chapter 93: Side by Side Comparisons of classic C++ examples solved via C++ vs C++11
vs C++14 vs C++17 ..................................................................................................................................................... 523
Section 93.1: Looping through a container ............................................................................................................. 523
Chapter 94: The This Pointer .............................................................................................................................. 524
Section 94.1: this Pointer ........................................................................................................................................... 524
Section 94.2: Using the this Pointer to Access Member Data ............................................................................... 526
Section 94.3: Using the this Pointer to Dierentiate Between Member Data and Parameters ........................ 526
Section 94.4: this Pointer CV-Qualifiers ................................................................................................................... 527
Section 94.5: this Pointer Ref-Qualifiers .................................................................................................................. 530
Chapter 95: Inline functions ................................................................................................................................ 532
Section 95.1: Non-member inline function definition ............................................................................................. 532
Section 95.2: Member inline functions .................................................................................................................... 532
Section 95.3: What is function inlining? ................................................................................................................... 532
Section 95.4: Non-member inline function declaration ......................................................................................... 533
Chapter 96: Copying vs Assignment ............................................................................................................... 534
Section 96.1: Assignment Operator ......................................................................................................................... 534
Section 96.2: Copy Constructor ............................................................................................................................... 534
Section 96.3: Copy Constructor Vs Assignment Constructor ............................................................................... 535
Chapter 97: Client server examples ................................................................................................................ 537
Section 97.1: Hello TCP Client ................................................................................................................................... 537
Section 97.2: Hello TCP Server ................................................................................................................................. 538
Chapter 98: Header Files ...................................................................................................................................... 542
Section 98.1: Basic Example ..................................................................................................................................... 542
Section 98.2: Templates in Header Files ................................................................................................................. 543
Chapter 99: Const Correctness .......................................................................................................................... 544
Section 99.1: The Basics ............................................................................................................................................ 544
Section 99.2: Const Correct Class Design ............................................................................................................... 544
Section 99.3: Const Correct Function Parameters ................................................................................................. 546
Section 99.4: Const Correctness as Documentation ............................................................................................. 548
Chapter 100: std::atomics ..................................................................................................................................... 552
Section 100.1: atomic types ...................................................................................................................................... 552
Chapter 101: Data Structures in C++ ............................................................................................................... 554
Section 101.1: Linked List implementation in C++ .................................................................................................... 554
Chapter 102: Refactoring Techniques ............................................................................................................ 557
Section 102.1: Goto Cleanup ..................................................................................................................................... 557
Chapter 103: C++ Streams .................................................................................................................................... 558
Section 103.1: String streams .................................................................................................................................... 558
Section 103.2: Printing collections with iostream ................................................................................................... 559
Chapter 104: Parameter packs ......................................................................................................................... 561
Section 104.1: A template with a parameter pack .................................................................................................. 561
Section 104.2: Expansion of a parameter pack ...................................................................................................... 561
Chapter 105: Literals ............................................................................................................................................... 562
Section 105.1: this ....................................................................................................................................................... 562
Section 105.2: Integer literal ..................................................................................................................................... 562
Section 105.3: true ..................................................................................................................................................... 563
Section 105.4: false .................................................................................................................................................... 564
Section 105.5: nullptr ................................................................................................................................................. 564
Chapter 106: Flow Control .................................................................................................................................... 565
Section 106.1: case ..................................................................................................................................................... 565
Section 106.2: switch .................................................................................................................................................. 565
Section 106.3: catch ................................................................................................................................................... 565
Section 106.4: throw .................................................................................................................................................. 566
Section 106.5: default ................................................................................................................................................ 567
Section 106.6: try ........................................................................................................................................................ 567
Section 106.7: if .......................................................................................................................................................... 567
Section 106.8: else ..................................................................................................................................................... 568
Section 106.9: Conditional Structures: if, if..else ...................................................................................................... 568
Section 106.10: goto ................................................................................................................................................... 569
Section 106.11: Jump statements : break, continue, goto, exit ............................................................................... 569
Section 106.12: return ................................................................................................................................................ 572
Chapter 107: Type Keywords .............................................................................................................................. 574
Section 107.1: class ..................................................................................................................................................... 574
Section 107.2: enum ................................................................................................................................................... 575
Section 107.3: struct ................................................................................................................................................... 576
Section 107.4: union ................................................................................................................................................... 576
Chapter 108: Basic Type Keywords ................................................................................................................. 578
Section 108.1: char ..................................................................................................................................................... 578
Section 108.2: char16_t ............................................................................................................................................. 578
Section 108.3: char32_t ............................................................................................................................................. 578
Section 108.4: int ........................................................................................................................................................ 578
Section 108.5: void ..................................................................................................................................................... 578
Section 108.6: wchar_t .............................................................................................................................................. 579
Section 108.7: float .................................................................................................................................................... 579
Section 108.8: double ................................................................................................................................................ 579
Section 108.9: long ..................................................................................................................................................... 579
Section 108.10: short .................................................................................................................................................. 580
Section 108.11: bool .................................................................................................................................................... 580
Chapter 109: Variable Declaration Keywords ............................................................................................ 581
Section 109.1: decltype .............................................................................................................................................. 581
Section 109.2: const ................................................................................................................................................... 581
Section 109.3: volatile ................................................................................................................................................ 582
Section 109.4: signed ................................................................................................................................................. 582
Section 109.5: unsigned ............................................................................................................................................. 582
Chapter 110: Iteration ............................................................................................................................................. 584
Section 110.1: break .................................................................................................................................................... 584
Section 110.2: continue .............................................................................................................................................. 584
Section 110.3: do ......................................................................................................................................................... 584
Section 110.4: while .................................................................................................................................................... 584
Section 110.5: range-based for loop ........................................................................................................................ 585
Section 110.6: for ........................................................................................................................................................ 585
Chapter 111: type deduction ................................................................................................................................. 586
Section 111.1: Template parameter deduction for constructors ............................................................................ 586
Section 111.2: Auto Type Deduction .......................................................................................................................... 586
Section 111.3: Template Type Deduction ................................................................................................................. 587
Chapter 112: std::any ............................................................................................................................................... 589
Section 112.1: Basic usage ......................................................................................................................................... 589
Chapter 113: C++11 Memory Model .................................................................................................................... 590
Section 113.1: Need for Memory Model .................................................................................................................... 590
Section 113.2: Fence example ................................................................................................................................... 591
Chapter 114: Build Systems ................................................................................................................................. 593
Section 114.1: Generating Build Environment with CMake ..................................................................................... 593
Section 114.2: Compiling with GNU make ................................................................................................................ 594
Section 114.3: Building with SCons ............................................................................................................................ 596
Section 114.4: Autotools (GNU) ................................................................................................................................. 596
Section 114.5: Ninja .................................................................................................................................................... 597
Section 114.6: NMAKE (Microsoft Program Maintenance Utility) .......................................................................... 597
Chapter 115: Concurrency With OpenMP ....................................................................................................... 598
Section 115.1: OpenMP: Parallel Sections ................................................................................................................. 598
Section 115.2: OpenMP: Parallel Sections ................................................................................................................ 598
Section 115.3: OpenMP: Parallel For Loop ............................................................................................................... 599
Section 115.4: OpenMP: Parallel Gathering / Reduction ........................................................................................ 599
Chapter 116: Type Inference ................................................................................................................................ 601
Section 116.1: Data Type: Auto .................................................................................................................................. 601
Section 116.2: Lambda auto ...................................................................................................................................... 601
Section 116.3: Loops and auto .................................................................................................................................. 601
Chapter 117: std::integer_sequence ................................................................................................................ 603
Section 117.1: Turn a std::tuple<T...> into function parameters .............................................................................. 603
Section 117.2: Create a parameter pack consisting of integers ........................................................................... 604
Section 117.3: Turn a sequence of indices into copies of an element .................................................................. 604
Chapter 118: Resource Management .............................................................................................................. 606
Section 118.1: Resource Acquisition Is Initialization ................................................................................................. 606
Section 118.2: Mutexes & Thread Safety .................................................................................................................. 607
Chapter 119: std::set and std::multiset ........................................................................................................... 609
Section 119.1: Changing the default sort of a set .................................................................................................... 609
Section 119.2: Deleting values from a set ................................................................................................................ 611
Section 119.3: Inserting values in a set ..................................................................................................................... 612
Section 119.4: Inserting values in a multiset ............................................................................................................ 614
Section 119.5: Searching values in set and multiset ............................................................................................... 614
Chapter 120: Storage class specifiers ............................................................................................................ 616
Section 120.1: extern .................................................................................................................................................. 616
Section 120.2: register ............................................................................................................................................... 617
Section 120.3: static ................................................................................................................................................... 617
Section 120.4: auto .................................................................................................................................................... 618
Section 120.5: mutable .............................................................................................................................................. 618
Chapter 121: Alignment .......................................................................................................................................... 620
Section 121.1: Controlling alignment ......................................................................................................................... 620
Section 121.2: Querying the alignment of a type ................................................................................................... 620
Chapter 122: Inline variables ............................................................................................................................... 622
Section 122.1: Defining a static data member in the class definition ................................................................... 622
Chapter 123: Linkage specifications ................................................................................................................ 623
Section 123.1: Signal handler for Unix-like operating system ............................................................................... 623
Section 123.2: Making a C library header compatible with C++ ........................................................................... 623
Chapter 124: Curiously Recurring Template Pattern (CRTP) ............................................................. 625
Section 124.1: The Curiously Recurring Template Pattern (CRTP) ....................................................................... 625
Section 124.2: CRTP to avoid code duplication ...................................................................................................... 626
Chapter 125: Using declaration ......................................................................................................................... 628
Section 125.1: Importing names individually from a namespace ......................................................................... 628
Section 125.2: Redeclaring members from a base class to avoid name hiding ................................................. 628
Section 125.3: Inheriting constructors ...................................................................................................................... 628
Chapter 126: Typedef and type aliases ......................................................................................................... 630
Section 126.1: Basic typedef syntax ......................................................................................................................... 630
Section 126.2: More complex uses of typedef ........................................................................................................ 630
Section 126.3: Declaring multiple types with typedef ............................................................................................ 631
Section 126.4: Alias declaration with "using" .......................................................................................................... 631
Chapter 127: Layout of object types .............................................................................................................. 632
Section 127.1: Class types .......................................................................................................................................... 632
Section 127.2: Arithmetic types ................................................................................................................................ 634
Section 127.3: Arrays ................................................................................................................................................. 635
Chapter 128: C incompatibilities ........................................................................................................................ 636
Section 128.1: Reserved Keywords ........................................................................................................................... 636
Section 128.2: Weakly typed pointers ..................................................................................................................... 636
Section 128.3: goto or switch .................................................................................................................................... 636
Chapter 129: std::forward_list ........................................................................................................................... 637
Section 129.1: Example .............................................................................................................................................. 637
Section 129.2: Methods ............................................................................................................................................. 637
Chapter 130: Optimization .................................................................................................................................... 639
Section 130.1: Inline Expansion/Inlining ................................................................................................................... 639
Section 130.2: Empty base optimization ................................................................................................................. 639
Chapter 131: Semaphore ....................................................................................................................................... 641
Section 131.1: Semaphore C++ 11 ............................................................................................................................... 641
Section 131.2: Semaphore class in action ................................................................................................................ 641
Chapter 132: Thread synchronization structures ..................................................................................... 643
Section 132.1: std::condition_variable_any, std::cv_status .................................................................................... 643
Section 132.2: std::shared_lock ................................................................................................................................ 643
Section 132.3: std::call_once, std::once_flag ........................................................................................................... 643
Section 132.4: Object locking for ecient access .................................................................................................. 644
Chapter 133: C++ Debugging and Debug-prevention Tools & Techniques ................................. 646
Section 133.1: Static analysis ..................................................................................................................................... 646
Section 133.2: Segfault analysis with GDB .............................................................................................................. 647
Section 133.3: Clean code ......................................................................................................................................... 648
Chapter 134: Futures and Promises ................................................................................................................ 650
Section 134.1: Async operation classes .................................................................................................................... 650
Section 134.2: std::future and std::promise .............................................................................................................. 650
Section 134.3: Deferred async example .................................................................................................................. 650
Section 134.4: std::packaged_task and std::future ................................................................................................. 651
Section 134.5: std::future_error and std::future_errc ............................................................................................. 651
Section 134.6: std::future and std::async .................................................................................................................. 652
Chapter 135: More undefined behaviors in C++ ......................................................................................... 655
Section 135.1: Referring to non-static members in initializer lists ......................................................................... 655
Chapter 136: Mutexes .............................................................................................................................................. 656
Section 136.1: Mutex Types ....................................................................................................................................... 656
Section 136.2: std::lock ............................................................................................................................................... 656
Section 136.3: std::unique_lock, std::shared_lock, std::lock_guard ...................................................................... 656
Section 136.4: Strategies for lock classes: std::try_to_lock, std::adopt_lock, std::defer_lock ........................... 657
Section 136.5: std::mutex ........................................................................................................................................... 658
Section 136.6: std::scoped_lock (C++ 17) ................................................................................................................. 658
Chapter 137: Unit Testing in C++ ....................................................................................................................... 659
Section 137.1: Google Test ......................................................................................................................................... 659
Section 137.2: Catch ................................................................................................................................................... 659
Chapter 138: Recursive Mutex ............................................................................................................................ 661
Section 138.1: std::recursive_mutex .......................................................................................................................... 661
Chapter 139: decltype ............................................................................................................................................. 662
Section 139.1: Basic Example .................................................................................................................................... 662
Section 139.2: Another example ............................................................................................................................... 662
Chapter 140: Using std::unordered_map .................................................................................................... 663
Section 140.1: Declaration and Usage ..................................................................................................................... 663
Section 140.2: Some Basic Functions ...................................................................................................................... 663
Chapter 141: Digit separators ............................................................................................................................ 664
Section 141.1: Digit Separator .................................................................................................................................... 664
Chapter 142: C++ function "call by value" vs. "call by reference" .................................................. 665
Section 142.1: Call by value ....................................................................................................................................... 665
Chapter 143: Basic input/output in c++ ........................................................................................................ 667
Section 143.1: user input and standard output ....................................................................................................... 667
Chapter 144: Stream manipulators ................................................................................................................ 668
Section 144.1: Stream manipulators ......................................................................................................................... 668
Section 144.2: Output stream manipulators ........................................................................................................... 673
Section 144.3: Input stream manipulators .............................................................................................................. 675
Chapter 145: C++ Containers .............................................................................................................................. 677
Section 145.1: C++ Containers Flowchart ................................................................................................................. 677
Chapter 146: Arithmitic Metaprogramming ................................................................................................ 678
Section 146.1: Calculating power in O(log n) ........................................................................................................... 678
Credits ............................................................................................................................................................................ 680
You may also like ...................................................................................................................................................... 687
About
Please feel free to share this PDF with anyone for free,
latest version of this book can be downloaded from:
http://GoalKicker.com/CPlusPlusBook
This C++ Notes for Professionals book is compiled from Stack Overflow
Documentation, the content is written by the beautiful people at Stack Overflow.
Text content is released under Creative Commons BY-SA, see credits at the end
of this book whom contributed to the various chapters. Images may be copyright
of their respective owners unless otherwise specified
This is an unofficial free book created for educational purposes and is not
affiliated with official C++ group(s) or company(s) nor Stack Overflow. All
trademarks and registered trademarks are the property of their respective
company owners
#include <iostream>
int main()
{
std::cout << "Hello World!" << std::endl;
}
Analysis
#include <iostream> is a preprocessor directive that includes the content of the standard C++ header file
iostream.
iostream is a standard library header file that contains definitions of the standard input and output
streams. These definitions are included in the std namespace, explained below.
The standard input/output (I/O) streams provide ways for programs to get input from and output to an
external system -- usually the terminal.
int main() { ... } defines a new function named main. By convention, the main function is called upon
execution of the program. There must be only one main function in a C++ program, and it must always return
a number of the int type.
Here, the int is what is called the function's return type. The value returned by the main function is an exit
code.
By convention, a program exit code of 0 or EXIT_SUCCESS is interpreted as success by a system that executes
the program. Any other return code is associated with an error.
If no return statement is present, the main function (and thus, the program itself) returns 0 by default. In this
example, we don't need to explicitly write return 0;.
All other functions, except those that return the void type, must explicitly return a value according to their
return type, or else must not return at all.
std is a namespace, and :: is the scope resolution operator that allows look-ups for objects by name
within a namespace.
There are many namespaces. Here, we use :: to show we want to use cout from the std namespace.
For more information refer to Scope Resolution Operator - Microsoft Documentation.
std::cout is the standard output stream object, defined in iostream, and it prints to the standard
output (stdout).
<< is, in this context, the stream insertion operator, so called because it inserts an object into the
stream object.
The standard library defines the << operator to perform data insertion for certain data types into
output streams. stream << content inserts content into the stream and returns the same, but
updated stream. This allows stream insertions to be chained: std::cout << "Foo" << " Bar"; prints
"FooBar" to the console.
"Hello World!" is a character string literal, or a "text literal." The stream insertion operator for
character string literals is defined in file iostream.
std::endl is a special I/O stream manipulator object, also defined in file iostream. Inserting a
manipulator into a stream changes the state of the stream.
The stream manipulator std::endl does two things: first it inserts the end-of-line character and then it
flushes the stream buffer to force the text to show up on the console. This ensures that the data
inserted into the stream actually appear on your console. (Stream data is usually stored in a buffer and
then "flushed" in batches unless you force a flush immediately.)
The semicolon (;) notifies the compiler that a statement has ended. All C++ statements and class
definitions require an ending/terminating semicolon.
Single-Line Comments
The double forward-slash sequence // will mark all text until a newline as a comment:
C-Style/Block Comments
The sequence /* is used to declare the start of the comment block and the sequence */ is used to declare the end
of comment. All text between the start and end sequences is interpreted as a comment, even if the text is
otherwise valid C++ syntax. These are sometimes called "C-style" comments, as this comment syntax is inherited
from C++'s predecessor language, C:
int main()
{
/*
* This is a block comment.
*/
int a;
}
In any block comment, you can write anything you want. When the compiler encounters the symbol */, it
terminates the block comment:
int main()
{
/* A block comment with the symbol /*
Note that the compiler is not affected by the second /*
however, once the end-block-comment symbol is reached,
the comment ends.
*/
int a;
}
The above example is valid C++ (and C) code. However, having additional /* inside a block comment might result in
a warning on some compilers.
Block comments can also start and end within a single line. For example:
Importance of Comments
The need for comments can be reduced by writing clear, self-documenting code. A simple example is the use of
During development, comments can also be used to quickly disable portions of code without deleting it. This is
often useful for testing or debugging purposes, but is not good style for anything other than temporary edits. This
is often referred to as “commenting out”.
Similarly, keeping old versions of a piece of code in a comment for reference purposes is frowned upon, as it
clutters files while offering little value compared to exploring the code's history via a versioning system.
A compiler is a program that translates code from a programming language into another form which is (more)
directly executable for a computer. Using a compiler to translate code is called compilation.
C++ inherits the form of its compilation process from its "parent" language, C. Below is a list showing the four major
steps of compilation in C++:
1. The C++ preprocessor copies the contents of any included header files into the source code file, generates
macro code, and replaces symbolic constants defined using #define with their values.
2. The expanded source code file produced by the C++ preprocessor is compiled into assembly language
appropriate for the platform.
3. The assembler code generated by the compiler is assembled into appropriate object code for the platform.
4. The object code file generated by the assembler is linked together with the object code files for any library
functions used to produce an executable file.
Note: some compiled code is linked together, but not to create a final program. Usually, this "linked" code
can also be packaged into a format that can be used by other programs. This "bundle of packaged, usable
code" is what C++ programmers refer to as a library.
Many C++ compilers may also merge or un-merge certain parts of the compilation process for ease or for additional
analysis. Many C++ programmers will use different tools, but all of the tools will generally follow this generalized
process when they are involved in the production of a program.
The link below extends this discussion and provides a nice graphic to help. [1]:
http://faculty.cs.niu.edu/~mcmahon/CS241/Notes/compile.html
Functions can accept arguments or values and return a single value (or not). To use a function, a function call is
used on argument values and the use of the function call itself is replaced with its return value.
Every function has a type signature -- the types of its arguments and the type of its return type.
Functions are inspired by the concepts of the procedure and the mathematical function.
Note: C++ functions are essentially procedures and do not follow the exact definition or rules of
mathematical functions.
Note: popular function definitions may be hidden in other included files (often for convenience and reuse
across many files). This is a common use of header files.
Function Declaration
A function declaration is declares the existence of a function with its name and type signature to the compiler.
The syntax is as the following:
int add2(int i); // The function is of the type (int) -> (int)
In the example above, the int add2(int i) function declares the following to the compiler:
The argument name is optional; the declaration for the function could also be the following:
Per the one-definition rule, a function with a certain type signature can only be declared or defined once in an
entire C++ code base visible to the C++ compiler. In other words, functions with a specific type signature cannot be
re-defined -- they must only be defined once. Thus, the following is not valid C++:
int add2(int i); // The compiler will note that add2 is a function (int) -> int
int add2(int j); // As add2 already has a definition of (int) -> int, the compiler
// will regard this as an error.
If a function returns nothing, its return type is written as void. If it takes no parameters, the parameter list should
be empty.
void do_something(); // The function takes no parameters, and does not return anything.
// Note that it can still affect variables it has access to.
Function Call
A function can be called after it has been declared. For example, the following program calls add2 with the value of
2 within the function of main:
#include <iostream>
int main()
{
std::cout << add2(2) << "\n"; // add2(2) will be evaluated at this point,
// and the result is printed.
return 0;
Function Definition
A function definition* is similar to a declaration, except it also contains the code that is executed when the function
is called within its body.
int add2(int i) // Data that is passed into (int i) will be referred to by the name i
{ // while in the function's curly brackets or "scope."
Function Overloading
You can create multiple functions with the same name but different parameters.
int add2(int i, int j) // However, when add2() is called with two parameters, the
{ // code from the initial declaration will be overloaded,
int k = i + j + 2 ; // and the code in this declaration will be evaluated
return k; // instead.
}
Both functions are called by the same name add2, but the actual function that is called depends directly on the
amount and type of the parameters in the call. In most cases, the C++ compiler can compute which function to call.
In some cases, the type must be explicitly stated.
Default Parameters
Default values for function parameters can only be specified in function declarations.
In this example, multiply() can be called with one or two parameters. If only one parameter is given, b will have
default value of 7. Default arguments must be placed in the latter arguments of the function. For example:
There exist special function calls in C++ which have different syntax than name_of_function(value1, value2,
value3). The most common example is that of operators.
, *, %, and << and many more. These special characters are normally associated with non-programming usage or are
used for aesthetics (e.g. the + character is commonly recognized as the addition symbol both within C++
programming as well as in elementary math).
C++ handles these character sequences with a special syntax; but, in essence, each occurrence of an operator is
reduced to a function call. For example, the following C++ expression:
3+3
operator+(3, 3)
While in C++'s immediate predecessor, C, operator function names cannot be assigned different meanings by
providing additional definitions with different type signatures, in C++, this is valid. "Hiding" additional function
definitions under one unique function name is referred to as operator overloading in C++, and is a relatively
common, but not universal, convention in C++.
int main()
{
foo(2); // error: foo is called, but has not yet been declared
}
There are two ways to resolve this: putting either the definition or declaration of foo() before its usage in main().
Here is one example:
int main()
{
foo(2); // OK: foo is completely defined beforehand, so it can be called here.
}
However it is also possible to "forward-declare" the function by putting only a "prototype" declaration before its
usage and then defining the function body later:
The prototype must specify the return type (void), the name of the function (foo), and the argument list variable
types (int), but the names of the arguments are NOT required.
One common way to integrate this into the organization of source files is to make a header file containing all of the
prototype declarations:
// foo.h
void foo(int); // prototype declaration
and then, once compiled, link the corresponding object file foo.o into the compiled object file where it is used in
the linking phase, main.o:
An “unresolved external symbol” error occurs when the function prototype and call exist, but the function body is
not defined. These can be trickier to resolve as the compiler won't report the error until the final linking stage, and
it doesn't know which line to jump to in the code to show the error.
It edits the source code, cutting some bits out, changing others, and adding other things.
In source files, we can include preprocessor directives. These directives tells the preprocessor to perform specific
actions. A directive starts with a # on a new line. Example:
#define ZERO 0
#include <something>
directive. What it does is takes all of something and inserts it in your file where the directive was. The hello world
program starts with the line
#include <iostream>
This line adds the functions and objects that let you use the standard input and output.
The C language, which also uses the preprocessor, does not have as many header files as the C++ language, but in
directive. This tells the preprocessor that as it goes along the file, it should replace every occurrence of something
with something_else. It can also make things similar to functions, but that probably counts as advanced C++.
The something_else is not needed, but if you define something as nothing, then outside preprocessor directives, all
occurrences of something will vanish.
This actually is useful, because of the #if,#else and #ifdef directives. The format for these would be the following:
#if something==true
//code
#else
//more code
#endif
#ifdef thing_that_you_want_to_know_if_is_defined
//code
#endif
These directives insert the code that is in the true bit, and deletes the false bits. this can be used to have bits of
code that are only included on certain operating systems, without having to rewrite the whole code.
#include <iostream>
using std::cout;
template <typename T> // A simple class to hold one number of any type
class Number {
public:
void setNum(T n); // Sets the class field to the given number
T plus1() const; // returns class field's "follower"
private:
T num; // Class field
};
template <typename T> // Set the class field to the given number
void Number<T>::setNum(T n) {
num = n;
}
int main() {
Number<int> anInt; // Test with an integer (int replaces T in the class)
anInt.setNum(1);
cout << "My integer + 1 is " << anInt.plus1() << "\n"; // Prints 2
printSum<int>(4, 5);
printSum<float>(4.5f, 8.9f);
In both these case the template argument is used to replace the types of the parameters; the result works just like
a normal C++ function (if the parameters don't match the template type the compiler applies the standard
conversions).
One additional property of template functions (unlike template classes) is that the compiler can infer the template
parameters based on the parameters passed to the function.
printSum(5.0, 4); // In this case the parameters are two different types.
// The compiler is unable to deduce the type of T
// because there are contradictions. As a result
// this is a compile time error.
This feature allows us to simplify code when we combine template structures and functions. There is a common
pattern in the standard library that allows us to make template structure X using a helper function make_X().
auto val1 = MyPair<int, float>{5, 8.7}; // Create object explicitly defining the types
auto val2 = make_MyPair(5, 8.7); // Create object using the types of the paramters.
// In this code both val1 and val2 are the same
// type.
Note: This is not designed to shorten the code. This is designed to make the code more robust. It allows the types
to be changed by changing the code in a single place rather than in multiple locations.
It is often useful to define classes or structures that have a variable number and type of data members which are
defined at compile time. The canonical example is std::tuple, but sometimes is it is necessary to define your own
custom structures. Here is an example that defines the structure using compounding (rather than inheritance as
with std::tuple. Start with the general (empty) definition, which also serves as the base-case for recrusion
termination in the later specialisation:
This already allows us to define an empty structure, DataStructure<> data, albeit that isn't very useful yet.
T first;
DataStructure<Rest ... > rest;
};
This is now sufficient for us to create arbitrary data structures, like DataStructure<int, float, std::string>
data(1, 2.1, "hello").
So what's going on? First, note that this is a specialisation whose requirement is that at least one variadic template
parameter (namely T above) exists, whilst not caring about the specific makeup of the pack Rest. Knowing that T
exists allows the definition of its data member, first. The rest of the data is recursively packaged as
DataStructure<Rest ... > rest. The constructor initiates both of those members, including a recursive
constructor call to the rest member.
To understand this better, we can work through an example: suppose you have a declaration DataStructure<int,
float> data. The declaration first matches against the specialisation, yielding a structure with int first and
DataStructure<float> rest data members. The rest definition again matches this specialisation, creating its own
float first and DataStructure<> rest members. Finally this last rest matches against the base-case defintion,
producing an empty structure.
DataStructure<int, float>
-> int first
-> DataStructure<float> rest
-> float first
-> DataStructure<> rest
-> (empty)
Now we have the data structure, but its not terribly useful yet as we cannot easily access the individual data
elements (for example to access the last member of DataStructure<int, float, std::string> data we would
have to use data.rest.rest.first, which is not exactly user-friendly). So we add a get method to it (only needed
As you can see this get member function is itself templated - this time on the index of the member that is needed
(so usage can be things like data.get<1>(), similar to std::tuple). The actual work is done by a static function in a
helper class, GetHelper. The reason we can't define the required functionality directly in DataStructure's get is
because (as we will shortly see) we would need to specialise on idx - but it isn't possible to specialise a template
member function without specialising the containing class template. Note also the use of a C++14-style auto here
makes our lives significantly simpler as otherwise we would need quite a complicated expression for the return
type.
So on to the helper class. This time we will need an empty forward declaration and two specialisations. First the
declaration:
Now the base-case (when idx==0). In this case we just return the first member:
In the recursive case, we decrement idx and invoke the GetHelper for the rest member:
To work through an example, suppose we have DataStructure<int, float> data and we need data.get<1>().
This invokes GetHelper<1, DataStructure<int, float>>::get(data) (the 2nd specialisation), which in turn
invokes GetHelper<0, DataStructure<float>>::get(data.rest), which finally returns (by the 1st specialisation as
now idx is 0) data.rest.first.
So that's it! Here is the whole functioning code, with some example use in the main function:
T first;
DataStructure<Rest ... > rest;
template<size_t idx>
auto get()
{
return GetHelper<idx, DataStructure<T,Rest...>>::get(*this);
}
};
int main()
{
DataStructure<int, float, std::string> data(1, 2.1, "Hello");
return 0;
}
In this case, the real type of t will be deduced depending on the context:
struct X { };
X x;
f(x); // calls f<X&>(x)
f(X()); // calls f<X>(x)
In the first case, the type T is deduced as reference to X (X&), and the type of t is lvalue reference to X, while in the
second case the type of T is deduced as X and the type of t as rvalue reference to X (X&&).
Note: It is worth noticing that in the first case, decltype(t) is the same as T, but not in the second.
In order to perfectly forward t to another function ,whether it is an lvalue or rvalue reference, one must use
std::forward:
Note: Forwarding references can only be used for template parameters, for instance, in the following code, v is a
rvalue reference, not a forwarding reference:
#include <vector>
// Common case:
template<typename T, typename U>
struct S {
T t_val;
U u_val;
};
As shown above, partial template specializations may introduce completely different sets of data and function
members.
When a partially specialized template is instantiated, the most suitable specialization is selected. For example, let's
define a template and two partial specializations:
template<typename V>
struct S<int, double, V> {
static void foo() {
std::cout << "T = int, U = double\n";
}
};
will print
General case
T = int
T = int, U = double
// OK.
template<>
void foo<int, int>(int a1, int a2) {
std::cout << "Two ints: " << a1 << " " << a2 << std::endl;
}
void invoke_foo() {
foo(1, 2.1); // Prints "General case: 1 2.1"
foo(1,2); // Prints "Two ints: 1 2"
}
template<>
int sqrt<int>(int i) { /* Highly optimized integer implementation */ }
Then a user that writes sqrt(4.0) will get the generic implementation whereas sqrt(4) will get the specialized
implementation.
Basic example:
Alias templates cannot be specialized. However, that functionality can be obtained indirectly by having them refer
to a nested type in a struct:
template<typename T>
struct nonconst_pointer_helper { typedef T* type; };
template<typename T>
struct nonconst_pointer_helper<T const> { typedef T* type; };
// print_string.h
template <class T>
void print_string(const T* str);
Version ≥ C++11
If an explicit instantiation definition is preceded by the extern keyword, it becomes an explicit instantiation
declaration instead. The presence of an explicit instantiation declaration for a given specialization prevents the
implicit instantiation of the given specialization within the current translation unit. Instead, a reference to that
specialization that would otherwise cause an implicit instantiation can refer to an explicit instantiation definition in
the same or another TU.
foo.h
#ifndef FOO_H
#define FOO_H
template <class T> void foo(T x) {
// complicated implementation
}
#endif
foo.cpp
#include "foo.h"
// explicit instantiation definitions for common cases
template void foo(int);
template void foo(double);
main.cpp
#include "foo.h"
// we already know foo.cpp has explicit instantiation definitions for these
extern template void foo(double);
int main() {
foo(42); // instantiates foo<int> here;
// wasteful since foo.cpp provides an explicit instantiation already!
foo(3.14); // does not instantiate foo<double> here;
// uses instantiation of foo<double> in foo.cpp instead
}
#include <iostream>
int main()
{
char anArrayOfChar[15];
std::cout << "anArrayOfChar: " << size_of(anArrayOfChar) << "\n";
#include <array>
int main ()
{
std::array<int, 5> foo; // int is a type parameter, 5 is non-type
}
Non-type template parameters are one of the ways to achieve template recurrence and enables to do
Metaprogramming.
But for complicated expressions, using something like this involves having to write decltype(expr), expr when
instantiating templates. The solution is to simplify this idiom and simply allow auto:
Version ≥ C++17
template <auto N>
struct integral_constant {
using type = decltype(N);
static constexpr type value = N;
};
A nice motivating example can come from trying to combine the empty base optimization with a custom deleter for
unique_ptr. Different C API deleters have different return types, but we don't care - we just want something to
work for any function:
And now you can simply use any function pointer that can take an argument of type T as a template non-type
parameter, regardless of return type, and get a no-size overhead unique_ptr out of it:
unique_ptr_deleter<std::FILE, std::fclose> p;
int main() {
IntTag<Tag1>::type t;
}
Version ≥ C++11
#include <vector>
#include <iostream>
int main() {
std::vector<float> vf = {1.2, 2.6, 3.7};
auto vi = cast_all<int>(vf);
for(auto &&i: vi) {
std::cout << i << std::endl;
}
int main() {
/* Default parameter is ignored, N = 5 */
my_array<int, 5> a;
In general, macros are frowned upon in this role and templates are preferred, although they are not as generic.
Template metaprogramming often makes use of compile-time computations, whether via templates or constexpr
functions, to achieve its goals of generating code, however compile-time computations are not metaprogramming
per se.
#include <iostream>
template<>
struct factorial<0>
{
enum { value = 1 };
};
int main()
{
std::cout << factorial<7>::value << std::endl; // prints "5040"
}
In the above code, we evaluate the factorial metafunction by instantiating the template with the parameters we
want to pass, and using ::value to get the result of the evaluation.
The metafunction itself relies on recursively instantiating the same metafunction with smaller values. The
factorial<0> specialization represents the terminating condition. Template metaprogramming has most of the
restrictions of a functional programming language, so recursion is the primary "looping" construct.
Since template metafunctions execute at compile time, their results can be used in contexts that require compile-
time values. For example:
int my_array[factorial<5>::value];
Automatic arrays must have a compile-time defined size. And the result of a metafunction is a compile-time
constant, so it can be used here.
Limitation: Most of the compilers won't allow recursion depth beyond a limit. For example, g++ compiler by default
Version ≥ C++11
Since C++11, the std::integral_constant template can be used for this kind of template computation:
#include <iostream>
#include <type_traits>
template<>
struct factorial<0> :
std::integral_constant<long long, 1> {};
int main()
{
std::cout << factorial<7>::value << std::endl; // prints "5040"
}
#include <iostream>
int main()
{
char test[factorial(3)];
std::cout << factorial(7) << '\n';
}
The body of factorial() is written as a single statement because in C++11 constexpr functions can only use a
quite limited subset of the language.
Version ≥ C++14
Since C++14, many restrictions for constexpr functions have been dropped and they can now be written much
more conveniently:
Or even:
#include <iostream>
#include <utility>
int main() {
std::cout << factorial<int, 5>::value << std::endl;
}
Version ≥ C++11
void print_all(std::ostream& os) {
// base case
}
print_all(os, rest...);
}
We could instead use the expander trick, to perform all the streaming in a single function. This has the advantage of
not needing a second overload, but has the disadvantage of less than stellar readability:
Version ≥ C++11
template <class... Ts>
void print_all(std::ostream& os, Ts const&... args) {
using expander = int[];
(void)expander{0,
(void(os << args), 0)...
};
}
Version ≥ C++17
With C++17, we get two powerful new tools in our arsenal for solving this problem. The first is a fold-expression:
And the second is if constexpr, which allows us to write our original recursive solution in a single function:
template<std::size_t N>
using make_index_sequence = make_integer_sequence<std::size_t, N>;
While this comes standard in C++14, this can be implemented using C++11 tools.
We can use this tool to call a function with a std::tuple of arguments (standardized in C++17 as std::apply):
namespace detail {
template <class F, class Tuple, std::size_t... Is>
decltype(auto) apply_impl(F&& f, Tuple&& tpl, std::index_sequence<Is...> ) {
return std::forward<F>(f)(std::get<Is>(std::forward<Tuple>(tpl))...);
}
}
namespace details {
template <class RAIter, class Distance>
void advance(RAIter& it, Distance n, std::random_access_iterator_tag) {
it += n;
}
The std::XY_iterator_tag arguments of the overloaded details::advance functions are unused function
parameters. The actual implementation does not matter (actually it is completely empty). Their only purpose is to
allow the compiler to select an overload based on which tag class details::advance is called with.
In this example, advance uses the iterator_traits<T>::iterator_category metafunction which returns one of
the iterator_tag classes, depending on the actual type of Iter. A default-constructed object of the
iterator_category<Iter>::type then lets the compiler select one of the different overloads of details::advance.
(This function parameter is likely to be completely optimized away, as it is a default-constructed object of an empty
struct and never used.)
Tag dispatching can give you code that's much easier to read than the equivalents using SFINAE and enable_if.
Note: while C++17's if constexpr may simplify the implementation of advance in particular, it is not suitable for open
implementations unlike tag dispatching.
template<class T>
struct has_hash<T, decltype(std::hash<T>()(std::declval<T>()), void())>
: std::true_type
{};
Version ≥ C++17
template<class T>
struct has_hash<T, std::void_t< decltype(std::hash<T>()(std::declval<T>())) > >
: std::true_type
{};
For detecting if an operator, such as operator< is defined, the syntax is almost the same:
template<class T>
struct has_less_than<T, decltype(std::declval<T>() < std::declval<T>(), void())>
: std::true_type
{};
These can be used to use a std::unordered_map<T> if T has an overload for std::hash, but otherwise attempt to
use a std::map<T>:
The type std::conditional in the standard library header <type_traits> can select one type or the other, based
on a compile-time boolean value:
template<typename T>
struct ValueOrPointer
{
typename std::conditional<(sizeof(T) > sizeof(void*)), T*, T>::type vop;
};
This struct contains a pointer to T if T is larger than the size of a pointer, or T itself if it is smaller or equal to a
pointer's size. Therefore sizeof(ValueOrPointer) will always be <= sizeof(void*).
To help us with that, the standard already provides two types analog to true and false which are std::true_type
and std::false_type.
The following example show how to detect if a type T is a pointer or not, the is_pointer template mimic the
behavior of the standard std::is_pointer helper:
There are three steps in the above code (sometimes you only need two):
1. The first declaration of is_pointer_ is the default case, and inherits from std::false_type. The default case
should always inherit from std::false_type since it is analogous to a "false condition".
2. The second declaration specialize the is_pointer_ template for pointer T* without caring about what T is
really. This version inherits from std::true_type.
3. The third declaration (the real one) simply remove any unnecessary information from T (in this case we
remove const and volatile qualifiers) and then fall backs to one of the two previous declarations.
Use ::value, e.g. is_pointer<int>::value – value is a static class member of type bool inherited from
std::true_type or std::false_type;
Construct an object of this type, e.g. is_pointer<int>{} – This works because std::is_pointer inherits its
It is a good habit to provides "helper helper templates" that let you directly access the value:
In C++17 and above, most helper templates already provide a _v version, e.g.:
Keyword constexpr is responsible for calculating function in compilation time, then and only then, when all the
requirements for this will be met (see more at constexpr keyword reference) for example all the arguments must
be known at compile time.
Note: In C++11 constexpr function must compose only from one return statement.
Advantages: Comparing this to the standard way of compile time calculation, this method is also useful for runtime
calculations. It means, that if the arguments of the function are not known at the compilation time (e.g. value and
power are given as input via user), then function is run in a compilation time, so there's no need to duplicate a code
(as we would be forced in older standards of C++).
E.g.
void useExample() {
constexpr int compileTimeCalculated = calculatePower(3, 3); // computes at compile time,
// as both arguments are known at compilation time
// and used for a constant expression.
int value;
std::cin >> value;
int runtimeCalculated = calculatePower(value, 3); // runtime calculated,
// because value is known only at runtime.
}
Version ≥ C++17
Another way to calculate power at compile time can make use of fold expression as follows:
#include <iostream>
#include <utility>
int main() {
std::cout << power<int, 4, 2>::value << std::endl;
}
It's possible to write a generic function (for example min) which accepts various numerical types and arbitrary
argument count by template meta-programming. This function declares a min for two arguments and recursively
for more.
Iterators are a means of navigating and operating on a sequence of elements and are a generalized extension of
pointers. Conceptually it is important to remember that iterators are positions, not elements. For example, take the
following sequence:
A B C
+---+---+---+---+
| A | B | C | |
+---+---+---+---+
Elements are things within a sequence. Positions are places where meaningful operations can happen to the
sequence. For example, one inserts into a position, before or after element A, not into an element. Even deletion of
an element (erase(A)) is done by first finding its position, then deleting it.
One can think of an iterator as dereferencing to the value it refers to in the sequence. This is especially useful in
understanding why you should never dereference the end() iterator in a sequence:
+---+---+---+---+
| A | B | C | |
+---+---+---+---+
? ?
| +-- An iterator here has no value. Do not dereference it!
+-------------- An iterator here dereferences to the value A.
In all the sequences and containers found in the C++ standard library, begin() will return an iterator to the first
position, and end() will return an iterator to one past the last position (not the last position!). Consequently, the
names of these iterators in algorithms are oftentimes labelled first and last:
+---+---+---+---+
| A | B | C | |
+---+---+---+---+
? ?
| |
+- first +- last
It is also possible to obtain an iterator to any sequence, because even an empty sequence contains at least one
+---+
| |
+---+
In an empty sequence, begin() and end() will be the same position, and neither can be dereferenced:
+---+
| |
+---+
?
|
+- empty_sequence.begin()
|
+- empty_sequence.end()
The alternative visualization of iterators is that they mark the positions between elements:
+---+---+---+
| A | B | C |
+---+---+---+
? ^ ^ ?
| |
+- first +- last
and dereferencing an iterator returns a reference to the element coming after the iterator. Some situations where
this view is particularly useful are:
insert operations will insert elements into the position indicated by the iterator,
erase operations will return an iterator corresponding to the same position as the one passed in,
an iterator and its corresponding reverse iterator are located in the same .position between elements
Invalid Iterators
An iterator becomes invalidated if (say, in the course of an operation) its position is no longer a part of a sequence.
An invalidated iterator cannot be dereferenced until it has been reassigned to a valid position. For example:
std::vector<int>::iterator first;
{
std::vector<int> foo;
first = foo.begin(); // first is now valid
} // foo falls out of scope and is destroyed
// At this point first is now invalid
The many algorithms and sequence member functions in the C++ standard library have rules governing when
iterators are invalidated. Each algorithm is different in the way they treat (and invalidate) iterators.
As we know, iterators are for navigating sequences. In order to do that an iterator must migrate its position
throughout the sequence. Iterators can advance forward in the sequence and some can advance backwards:
Note, second argument of std::distance should be reachable from the first one(or, in other words first should be
less or equal than second).
Even though you can perform arithmetic operators with iterators, not all operations are defined for all types of
iterators. a = b + 3; would work for Random Access Iterators, but wouldn't work for Forward or Bidirectional
Iterators, which still can be advanced by 3 position with something like b = a; ++b; ++b; ++b;. So it is
recommended to use special functions in case you are not sure what is iterator type (for example, in a template
function accepting iterator).
Iterator Concepts
The C++ standard describes several different iterator concepts. These are grouped according to how they behave in
the sequences they refer to. If you know the concept an iterator models (behaves like), you can be assured of the
behavior of that iterator regardless of the sequence to which it belongs. They are often described in order from the
most to least restrictive (because the next iterator concept is a step better than its predecessor):
Input Iterators : Can be dereferenced only once per position. Can only advance, and only one position at a
time.
Forward Iterators : An input iterator that can be dereferenced any number of times.
Bidirectional Iterators : A forward iterator that can also advance backwards one position at a time.
Random Access Iterators : A bidirectional iterator that can advance forwards or backwards any number of
positions at a time.
Contiguous Iterators (since C++17) : A random access iterator that guaranties that underlying data is
contiguous in memory.
Algorithms can vary depending on the concept modeled by the iterators they are given. For example, although
random_shuffle can be implemented for forward iterators, a more efficient variant that requires random access
iterators could be provided.
Iterator traits
Iterator traits provide uniform interface to the properties of iterators. They allow you to retrieve value, difference,
pointer, reference types and also category of iterator:
template<class Iter>
Iter find(Iter first, Iter last, typename std::iterator_traits<Iter>::value_type val) {
while (first != last) {
if (*first == val)
return first;
++first;
}
return last;
}
template<class BidirIt>
template<class ForwIt>
void test(ForwIt a, std::forward_iterator_tag) {
std::cout << "Forward iterator is used" << std::endl;
}
template<class Iter>
void test(Iter a) {
test(a, typename std::iterator_traits<Iter>::iterator_category());
}
Categories of iterators are basically iterators concepts, except Contiguous Iterators don't have their own tag, since it
was found to break code.
If the vector object is const, both begin and end return a const_iterator. If you want a const_iterator to be
returned even if your vector is not const, you can use cbegin and cend.
Example:
#include <vector>
#include <iostream>
int main() {
std::vector<int> v = { 1, 2, 3, 4, 5 }; //intialize vector using an initializer_list
return 0;
}
Output:
12345
If a map object is const-qualified, the function returns a const_iterator. Otherwise, it returns an iterator.
Output:
a => 200
b => 100
c => 300
To iterate backwards use rbegin() and rend() as the iterators for the end of the collection, and the start of the
collection respectively.
A reverse iterator can be converted to a forward iterator via the base() member function. The relationship is that
the reverse iterator references one element past the base() iterator:
std::vector<int>::reverse_iterator r = v.rbegin();
std::vector<int>::iterator i = r.base();
assert(&*r == &*(i-1)); // always true if r, (i-1) are dereferenceable
// and are not proxy iterators
+---+---+---+---+---+---+---+
| | 1 | 2 | 3 | 4 | 5 | |
+---+---+---+---+---+---+---+
? ? ? ?
| | | |
rend() | rbegin() end()
| rbegin().base()
begin()
rend().base()
In the visualization where iterators mark positions between elements, the relationship is simpler:
+---+---+---+---+---+
| 1 | 2 | 3 | 4 | 5 |
+---+---+---+---+---+
? ?
| |
| end()
| rbegin()
begin() rbegin().base()
rend()
rend().base()
// Constructing stream iterators and copying data from stream into vector.
std::copy(
// Iterator which will read stream data as integers.
std::istream_iterator<int>(istr),
// Default constructor produces end-of-stream iterator.
std::istream_iterator<int>(),
std::back_inserter(v));
#ifdef BEFORE_CPP11
// You can use `sizeof` to determine how many elements are in an array.
const int* first = array;
const int* afterLast = first + sizeof(array) / sizeof(array[0]);
// Then you can iterate over the array by incrementing a pointer until
// it reaches past the end of our array.
for (const int* i = first; i < afterLast; ++i) {
std::cout << *i << std::endl;
}
#else
// With C++11, you can let the STL compute the start and end iterators:
for (auto i = std::begin(array); i != std::end(array); ++i) {
std::cout << *i << std::endl;
}
#endif
This code would output the numbers 1 through 5, one on each line like this:
1
2
3
4
Breaking It Down
const int array[] = { 1, 2, 3, 4, 5 };
This line creates a new integer array with 5 values. C arrays are just pointers to memory where each value is stored
together in a contiguous block.
These lines create two pointers. The first pointer is given the value of the array pointer, which is the address of the
first element in the array. The sizeof operator when used on a C array returns the size of the array in bytes.
Divided by the size of an element this gives the number of elements in the array. We can use this to find the
address of the block after the array.
Here we create a pointer which we will use as an iterator. It is initialized with the address of the first element we
want to iterate over, and we'll continue to iterate as long as i is less than afterLast, which means as long as i is
pointing to an address within array.
Finally, within the loop we can access the value our iterator i is pointing to by dereferencing it. Here the
dereference operator * returns the value at the address in i.
template<class T>
struct generator_iterator {
using difference_type=std::ptrdiff_t;
using value_type=T;
using pointer=T*;
using reference=T;
using iterator_category=std::input_iterator_tag;
std::optional<T> state;
std::function< std::optional<T>() > operation;
// we store the current element in "state" if we have one:
T operator*() const {
return *state;
}
// to advance, we invoke our operation. If it returns a nullopt
// we have reached the end:
generator_iterator& operator++() {
state = operation();
return *this;
}
generator_iterator operator++(int) {
auto r = *this;
live example.
We store the generated element early so we can more easily detect if we are already at the end.
As the function of an end generator iterator is never used, we can create a range of generator iterators by only
copying the std::function once. A default constructed generator iterator compares equal to itself, and to all other
end-generator-iterators.
The type std::tuple can bundle any number of values, potentially including values of different types, into a single
return object:
Version ≥ C++17
std::tuple<int, int, int, int> foo(int a, int b) {
return {a + b, a - b, a * b, a / b};
}
Retrieving values from the returned tuple can be cumbersome, requiring the use of the std::get template
function:
If the types can be declared before the function returns, then std::tie can be employed to unpack a tuple into
existing variables:
If you want to return a tuple of lvalue references instead of a tuple of values, use std::tie in place of
std::make_tuple.
which permits
In some rare cases you'll use std::forward_as_tuple instead of std::tie; be careful if you do so, as temporaries
may not last long enough to be consumed.
C++17 introduces structured bindings, which makes it even easier to deal with multiple return types, as you do not
need to rely upon std::tie() or do any manual tuple unpacking:
std::map<std::string, int> m;
if (success) {
// your code goes here
}
// iterate over all elements without having to use the cryptic 'first' and 'second' names
for (auto const& [key, value] : m) {
std::cout << "The value for " << key << " is " << value << '\n';
}
Structured bindings can be used by default with std::pair, std::tuple, and any type whose non-static data
members are all either public direct members or members of an unambiguous base class:
struct A { int x; };
struct B : A { int y; };
B foo();
If you make your type "tuple-like" it will also automatically work with your type. A tuple-like is a type with
appropriate tuple_size, tuple_element and get written:
namespace my_ns {
struct my_type {
int x;
namespace std {
template<>
struct tuple_size<my_ns::my_type_view> : std::integral_constant<std::size_t, 3>
{};
namespace my_ns {
template<std::size_t I>
decltype(auto) get(my_type_view const& v) {
if constexpr (I == 0)
return v.ptr->x;
else if constexpr (I == 1)
return v.ptr->d;
else if constexpr (I == 2)
return v.ptr->s;
static_assert(I < 3, "Only 3 elements");
}
}
my_ns::my_type_view foo() {
return {&t};
}
int main() {
auto[x, d, s] = foo();
std::cout << x << ',' << d << ',' << s << '\n';
}
Version ≥ C++11
struct foo_return_type {
int add;
int sub;
int mul;
int div;
};
Instead of assignment to individual fields, a constructor can be used to simplify the constructing of returned values:
struct foo_return_type {
int add;
int sub;
int mul;
int div;
foo_return_type(int add, int sub, int mul, int div)
: add(add), sub(sub), mul(mul), div(div) {}
};
The individual results returned by the function foo() can be retrieved by accessing the member variables of the
struct calc:
std::cout << calc.add << ' ' << calc.sub << ' ' << calc.mul << ' ' << calc.div << '\n';
Output:
17 -7 60 0
Note: When using a struct, the returned values are grouped together in a single object and accessible using
meaningful names. This also helps to reduce the number of extraneous variables created in the scope of the
returned values.
Version ≥ C++17
In order to unpack a struct returned from a function, structured bindings can be used. This places the out-
parameters on an even footing with the in-parameters:
The output of this code is identical to that above. The struct is still used to return the values from the function.
This permits you do deal with the fields individually.
References:
Pointers:
Some libraries or frameworks use an empty 'OUT' #define to make it abundantly obvious which parameters are
output parameters in the function signature. This has no functional impact, and will be compiled out, but makes the
function signature a bit clearer;
#define OUT
Version ≥ C++11
template <class F>
void foo(int a, int b, F consumer) {
consumer(a + b, a - b, a * b, a / b);
}
You can adapt a function returning a tuple into a continuation passing style function via:
Version ≥ C++17
template<class Tuple>
struct continuation {
Tuple t;
template<class F>
decltype(auto) operator->*(F&& f)&&{
return std::apply( std::forward<F>(f), std::move(t) );
}
};
std::tuple<int,int,int,int> foo(int a, int b);
#include <utility>
std::pair<int, int> foo(int a, int b) {
return std::make_pair(a+b, a-b);
}
Version ≥ C++11
#include <utility>
std::pair<int, int> foo(int a, int b) {
return {a+b, a-b};
}
The individual values of the returned std::pair can be retrieved by using the pair's first and second member
objects:
Output:
10
The container std::array can bundle together a fixed number of return values. This number has to be known at
compile-time and all return values have to be of the same type:
This replaces c style arrays of the form int bar[4]. The advantage being that various c++ std functions can now be
used on it. It also provides useful member functions like at which is a safe member access function with bound
checking, and size which allows you to return the size of the array without calculation.
Example:
Example usage:
std::vector<int> digits;
generate_sequence(0, 10, std::back_inserter(digits));
// digits now contains {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
#include <vector>
#include <iostream>
// the following function returns all integers between and including 'a' and 'b' in a vector
// (the function can return up to std::vector::max_size elements with the vector, given that
// the system's main memory can hold that many items)
std::vector<int> fillVectorFrom(int a, int b) {
std::vector<int> temp;
for (int i = a; i <= b; i++) {
temp.push_back(i);
}
return temp;
}
int main() {
// assigns the filled vector created inside the function to the new vector 'v'
std::vector<int> v = fillVectorFrom(1, 10);
1. str::strtok is the cheapest standard provided tokenization method, it also allows the delimiter to be
modified between tokens, but it incurs 3 difficulties with modern C++:
std::strtok cannot be used on multiple strings at the same time (though some implementations do
extend to support this, such as: strtok_s)
For the same reason std::strtok cannot be used on multiple threads simultaneously (this may
however be implementation defined, for example: Visual Studio's implementation is thread safe)
Calling std::strtok modifies the std::string it is operating on, so it cannot be used on const
strings, const char*s, or literal strings, to tokenize any of these with std::strtok or to operate on a
std::string who's contents need to be preserved, the input would have to be copied, then the copy
could be operated on
Generally any of these options cost will be hidden in the allocation cost of the tokens, but if the cheapest
algorithm is required and std::strtok's difficulties are not overcomable consider a hand-spun solution.
// String to tokenize
std::string str{ "The quick brown fox" };
// Vector to store tokens
vector<std::string> tokens;
Live Example
2. The std::istream_iterator uses the stream's extraction operator iteratively. If the input std::string is
white-space delimited this is able to expand on the std::strtok option by eliminating its difficulties, allowing
inline tokenization thereby supporting the generation of a const vector<string>, and by adding support for
multiple delimiting white-space character:
// String to tokenize
const std::string str("The quick \tbrown \nfox");
std::istringstream is(str);
// Vector to store tokens
const std::vector<std::string> tokens = std::vector<std::string>(
std::istream_iterator<std::string>(is),
std::istream_iterator<std::string>());
Live Example
3. The std::regex_token_iterator uses a std::regex to iteratively tokenize. It provides for a more flexible
delimiter definition. For example, non-delimited commas and white-space:
Live Example
Version ≥ C++17
The data() member function can be used to obtain a modifiable char*, which can be used to manipulate the
std::string object's data.
Version ≥ C++11
A modifiable char* can also be obtained by taking the address of the first character: &s[0]. Within C++11, this is
guaranteed to yield a well-formed, null-terminated string. Note that &s[0] is well-formed even if s is empty,
whereas &s.front() is undefined if s is empty.
Version ≥ C++11
std::string str("This is a string.");
const char* cstr = str.c_str(); // cstr points to: "This is a string.\0"
const char* data = str.data(); // data points to: "This is a string.\0"
// Copy the contents of str to untie lifetime from the std::string object
std::unique_ptr<char []> cstr = std::make_unique<char[]>(str.size() + 1);
// delete[] cstr_unsafe;
std::cout << cstr.get();
C++17 introduces std::string_view, which is simply a non-owning range of const chars, implementable as either
a pair of pointers or a pointer and a length. It is a superior parameter type for functions that requires non-
modifiable string data. Before C++17, there were three options for this:
void foo(const char* s, size_t len); // pre-C++17, two arguments, have to pass them
// both everywhere
void foo(const char* s); // pre-C++17, single argument, but need to call
// strlen()
It offers a useful subset of the functionality that std::string does, although some of the functions behave
differently:
//Bad way - 'string::substr' returns a new string (expensive if the string is long)
std::cout << str.substr(15, 10) << '\n';
#include <string>
#include <codecvt>
#include <locale>
std::string input_str = "this is a -string-, which is a sequence based on the -char- type.";
std::wstring input_wstr = L"this is a -wide- string, which is based on the -wchar_t- type.";
// conversion
std::string wstr_turned_to_str =
std::wstring_convert<std::codecvt_utf8<wchar_t>>().to_bytes(input_wstr);
In order to improve usability and/or readability, you can define functions to perform the conversion:
#include <string>
#include <codecvt>
#include <locale>
Sample usage:
Please note that char and wchar_t do not imply encoding, and gives no indication of size in bytes. For instance,
wchar_t is commonly implemented as a 2-bytes data type and typically contains UTF-16 encoded data under
Windows (or UCS-2 in versions prior to Windows 2000) and as a 4-bytes data type encoded using UTF-32 under
Linux. This is in contrast with the newer types char16_t and char32_t, which were introduced in C++11 and are
guaranteed to be large enough to hold any UTF16 or UTF32 "character" (or more precisely, code point) respectively.
==
All these functions use the underlying std::string::compare() method to perform the comparison, and return for
convenience boolean values. The operation of these functions may be interpreted as follows, regardless of the
operator
==
If str1.length() == str2.length() and each character pair matches, then returns true, otherwise returns
false.
operator!=:
If str1.length() != str2.length() or one character pair doesn't match, returns true, otherwise it returns
false.
operator< or operator>:
Finds the first different character pair, compares them then returns the boolean result.
operator<= or operator>=:
Finds the first different character pair, compares them then returns the boolean result.
Note: The term character pair means the corresponding characters in both strings of the same positions. For
better understanding, if two example strings are str1 and str2, and their lengths are n and m respectively, then
character pairs of both strings means each str1[i] and str2[i] pairs where i = 0, 1, 2, ..., max(n,m). If for any i
where the corresponding character does not exist, that is, when i is greater than or equal to n or m, it would be
considered as the lowest value.
Version ≥ C++11
To trim a sequence or string means to remove all leading and trailing elements (or characters) matching a certain
predicate. We first trim the trailing elements, because it doesn't involve moving any elements, and then trim the
Trimming the trailing elements involves finding the last element not matching the predicate, and erasing from there
on:
Trimming the leading elements involves finding the first element not matching the predicate and erasing up to
there:
To specialize the above for trimming whitespace in a std::string we can use the std::isspace() function as a
predicate:
If you wish to create a new sequence that is a trimmed copy, then you can use a separate function:
To replace a portion of a std::string you can use the method replace from std::string.
//Define string
std::string str = "Hello foo, bar and world!";
std::string alternate = "Hello foobar";
//1)
str.replace(6, 3, "bar"); //"Hello bar, bar and world!"
//2)
str.replace(str.begin() + 6, str.end(), "nobody!"); //"Hello nobody!"
//3)
str.replace(19, 5, alternate, 6, 6); //"Hello foo, bar and foobar!"
Version ≥ C++14
//4)
str.replace(19, 5, alternate, 6); //"Hello foo, bar and foobar!"
//5)
str.replace(str.begin(), str.begin() + 5, str.begin() + 6, str.begin() + 9);
//"foo foo, bar and world!"
//6)
str.replace(0, 5, 3, 'z'); //"zzz foo, bar and world!"
//7)
str.replace(str.begin() + 6, str.begin() + 9, 3, 'x'); //"Hello xxx, bar and world!"
Version ≥ C++11
//8)
str.replace(str.begin(), str.begin() + 5, { 'x', 'y', 'z' }); //"xyz foo, bar and world!"
#include <sstream>
int main()
{
int val = 4;
std::ostringstream str;
str << val;
std::string converted = str.str();
return 0;
}
template<class T>
std::string toString(const T& x)
{
std::ostringstream ss;
ss << x;
return ss.str();
}
Aside from streams, since C++11 you can also use the std::to_string (and std::to_wstring) function which is
overloaded for all fundamental types and returns the string representation of its parameter.
The first takes a starting position from which the returned substring should begin. The starting position must be
valid in the range (0, str.length()]:
The second takes a starting position and a total length of the new substring. Regardless of the length, the substring
will never go past the end of the source string:
Note that you can also call substr with no arguments, in this case an exact copy of the string is returned
operator[](n)
std::string::operator[] is not bounds-checked and does not throw an exception. The caller is responsible for
asserting that the index is within the range of the string:
at(n)
std::string::at is bounds checked, and will throw std::out_of_range if the index is not within the range of the
string:
Note: Both of these examples will result in undefined behavior if the string is empty.
front()
back()
Note that a range-and-a-half version of mismatch() existed prior to C++14, but this is unsafe in the case that the
second string is the shorter of the two.
We can still use the range-and-a-half version of std::mismatch(), but we need to first check that the first string is at
most as big as the second:
With std::string_view, we can write the direct comparison we want without having to worry about allocation
overhead or making copies:
std::string supports iterators, and so you can use a ranged based loop to iterate through each character:
You can use a "traditional" for loop to loop through every character:
Note that all of these functions stop parsing the input string as soon as they encounter a non-numeric character, so
"123abc" will be converted into 123.
The std::ato* family of functions converts C-style strings (character arrays) to integer or floating-point types:
However, use of these functions is discouraged because they return 0 if they fail to parse the string. This is bad
because 0 could also be a valid result, if for example the input string was "0", so it is impossible to determine if the
conversion actually failed.
The newer std::sto* family of functions convert std::strings to integer or floating-point types, and throw
exceptions if they could not parse their input. You should use these functions if possible:
Version ≥ C++11
std::string ten = "10";
Furthermore, these functions also handle octal and hex strings unlike the std::ato* family. The second parameter
is a pointer to the first unconverted character in the input string (not illustrated here), and the third parameter is
the base to use. 0 is automatic detection of octal (starting with 0) and hex (starting with 0x or 0X), and any other
value is the base to use
#include <iostream>
#include <codecvt>
#include <locale>
#include <string>
using namespace std;
int main() {
// converts between wstring and utf8 string
wstring_convert<codecvt_utf8_utf16<wchar_t>> wchar_to_utf8;
// converts between u16string and utf8 string
wstring_convert<codecvt_utf8_utf16<char16_t>, char16_t> utf16_to_utf8;
return 0;
}
Mind that Visual Studio 2015 provides supports for these conversion but a bug in their library implementation
requires to use a different template for wstring_convert when dealing with char16_t:
if (it != std::string::npos)
std::cout << "Found at position: " << it << '\n';
else
std::cout << "Not found!\n";
Found at position: 21
These functions can allow you to search for characters from the end of the string, as well as find the negative case
(ie. characters that are not in the string). Here is an example:
Found at position: 6
Note: Be aware that the above functions do not search for substrings, but rather for characters contained in the
search string. In this case, the last occurrence of 'g' was found at position 6 (the other characters weren't found).
namespace Example
{
const int test = 5;
const int test3 = test + 3; //Fails; `test` not found outside of namespace.
Namespaces are useful for grouping related definitions together. Take the analogy of a shopping mall. Generally a
shopping mall is split up into several stores, each store selling items from a specific category. One store might sell
electronics, while another store might sell shoes. These logical separations in store types help the shoppers find the
items they're looking for. Namespaces help c++ programmers, like shoppers, find the functions, classes, and
variables they're looking for by organizing them in a logical manner. Example:
namespace Electronics
{
int TotalStock;
class Headphones
{
// Description of a Headphone (color, brand, model number, etc.)
};
class Television
{
// Description of a Television (color, brand, model number, etc.)
};
}
namespace Shoes
{
int TotalStock;
class Sandal
{
// Description of a Sandal (color, brand, model number, etc.)
};
class Slipper
{
// Description of a Slipper (color, brand, model number, etc.)
};
}
There is a single namespace predefined, which is the global namespace that has no name, but can be denoted by
::. Example:
namespace Test
{
int call(int i);
Test::SomeClass data;
call_too(data); //Succeeds
call fails because none of its parameter types come from the Test namespace. call_too works because
SomeClass is a member of Test and therefore it qualifies for ADL rules.
ADL does not occur if normal unqualified lookup finds a class member, a function that has been declared at block
scope, or something that is not of function type. For example:
void foo();
namespace N {
struct X {};
void foo(X ) { std::cout << '1'; }
void qux(X ) { std::cout << '2'; }
}
struct C {
void foo() {}
void bar() {
foo(N::X{}); // error: ADL is disabled and C::foo() takes no arguments
}
};
void bar() {
extern void foo(); // redeclares ::foo
foo(N::X{}); // error: ADL is disabled and ::foo() doesn't take any arguments
int qux;
void baz() {
qux(N::X{}); // error: variable declaration disables ADL for "qux"
}
namespace Foo
{
void bar() {}
}
namespace Foo
{
void bar2() {}
}
If you don't want to write Foo:: in front of every stuff in the namespace Foo, you can use using namespace Foo; to
import every single thing out of Foo.
namespace Foo
{
void bar() {}
void baz() {}
}
//Import Foo
using namespace Foo;
bar(); //OK
baz(); //OK
It is also possible to import selected entities in a namespace rather than the whole namespace:
using Foo::bar;
bar(); //OK, was specifically imported
baz(); // Not OK, was not imported
A word of caution: using namespaces in header files is seen as bad style in most cases. If this is done, the
namespace is imported in every file that includes the header. Since there is no way of "un-using" a namespace, this
can lead to namespace pollution (more or unexpected symbols in the global namespace) or, worse, conflicts. See
this example for an illustration of the problem:
To call bar, you have to specify the namespace first, followed by the scope resolution operator :::
Foo::bar();
namespace A
{
namespace B
{
namespace C
{
void bar() {}
}
}
}
Version ≥ C++17
namespace A::B::C
{
void bar() {}
namespace {
int foo = 42;
}
It is recommended to never use unnamed namespaces in header files as this gives a version of the content for
every translation unit it is included in. This is especially important if you define non-const globals.
// foo.h
namespace {
std::string globalString;
}
// 1.cpp
#include "foo.h" //< Generates unnamed_namespace{1.cpp}::globalString ...
globalString = "Initialize";
// 2.cpp
#include "foo.h" //< Generates unnamed_namespace{2.cpp}::globalString ...
std::cout << globalString; //< Will always print the empty string
namespace other {
struct bob {};
}
namespace a::b {
template<>
struct qualifies<::other::bob> : std::true_type {};
}
You can enter both the a and b namespaces in one step with namespace a::b starting in C++17.
inline namespace includes the content of the inlined namespace in the enclosing namespace, so
namespace Outer
{
inline namespace Inner
{
void foo();
}
}
is mostly equivalent to
namespace Outer
{
namespace Inner
{
void foo();
}
using Inner::foo;
}
but element from Outer::Inner:: and those associated into Outer:: are identical.
So following is equivalent
Outer::foo();
Outer::Inner::foo();
The alternative using namespace Inner; would not be equivalent for some tricky parts as template specialization:
For
class MyCustomType;
namespace Outer
{
// outer.h
// include guard omitted for simplification
namespace Outer
{
inline namespace Inner
{
template <typename T>
void foo() { std::cout << "Generic"; }
}
}
// outer.h
// include guard omitted for simplification
namespace Outer
{
namespace Inner
{
template <typename T>
void foo() { std::cout << "Generic"; }
}
using namespace Inner;
// Specialization of `Outer::foo` is not possible
// it should be `Outer::Inner::foo`.
}
Inline namespace is a way to allow several version to cohabit and defaulting to the inline one
namespace MyNamespace
{
// Inline the last version
inline namespace Version2
{
void foo(); // New version
void bar();
}
namespace boost
{
namespace multiprecision
{
class Number ...
}
}
namespace boost
{
namespace multiprecision
{
class Number ...
}
}
However, it is easier to get confused over which namespace you are aliasing when you have something like this:
namespace boost
{
namespace multiprecision
{
class Number ...
}
}
namespace numeric
{
namespace multiprecision
{
class Number ...
}
}
Streams use std::locale, e.g., for details of the formatting and for translation between external encodings and the
internal encoding.
std::ofstream os("foo.txt");
if(os.is_open()){
os << "Hello World!";
}
Instead of <<, you can also use the output file stream's member function write():
std::ofstream os("foo.txt");
if(os.is_open()){
char data[] = "Foo";
After writing to a stream, you should always check if error state flag badbit has been set, as it indicates whether the
operation failed or not. This can be done by calling the output file stream's member function bad():
os << "Hello Badbit!"; // This operation might fail for any reason.
if (os.bad())
// Failed to write!
Alternatively, you can use the file stream's member function open():
std::ifstream ifs;
ifs.open("bar.txt"); // ifstream: Opens file "bar.txt" for reading only.
std::ofstream ofs;
ofs.open("bar.txt"); // ofstream: Opens file "bar.txt" for writing only.
std::fstream iofs;
iofs.open("bar.txt"); // fstream: Opens file "bar.txt" for reading and writing.
You should always check if a file has been opened successfully (even when writing). Failures can include: the file
doesn't exist, file hasn't the right access rights, file is already in use, disk errors occurred, drive disconnected ...
Checking can be done as follows:
When file path contains backslashes (for example, on Windows system) you should properly escape them:
If you want to open file with non-ASCII characters in path on Windows currently you can use non-standard wide
character path argument:
If you know how the data is formatted, you can use the stream extraction operator (>>). Let's assume you have a file
named foo.txt which contains the following data:
Then you can use the following code to read that data from the file:
// Define variables.
std::ifstream is("foo.txt");
std::string firstname, lastname;
int age, bmonth, bday, byear;
// Extract firstname, lastname, age, bday month, bday day, and bday year in that order.
// Note: '>>' returns false if it reached EOF (end of file) or if the input data doesn't
// correspond to the type of the input variable (for example, the string "foo" can't be
// extracted into an 'int' variable).
while (is >> firstname >> lastname >> age >> bmonth >> bday >> byear)
// Process the data that has been read.
The stream extraction operator >> extracts every character and stops if it finds a character that can't be stored or if
it is a special character:
This means that the following version of the file foo.txt will also be successfully read by the previous code:
John
Doe 25
4 6 1987
Jane
Doe
15 5
24
1976
The stream extraction operator >> always returns the stream given to it. Therefore, multiple operators can be
chained together in order to read data consecutively. However, a stream can also be used as a Boolean expression
(as shown in the while loop in the previous code). This is because the stream classes have a conversion operator
for the type bool. This bool() operator will return true as long as the stream has no errors. If a stream goes into an
error state (for example, because no more data can be extracted), then the bool() operator will return false.
Therefore, the while loop in the previous code will be exited after the input file has been read to its end.
If you wish to read an entire file as a string, you may use the following code:
// Opens 'foo.txt'.
std::ifstream is("foo.txt");
std::string whole_file;
This code reserves space for the string in order to cut down on unneeded memory allocations.
If you want to read a file line by line, you can use the function getline():
std::ifstream is("foo.txt");
If you want to read a fixed number of characters, you can use the stream's member function read():
std::ifstream is("foo.txt");
char str[4];
After executing a read command, you should always check if the error state flag failbit has been set, as it
indicates whether the operation failed or not. This can be done by calling the file stream's member function fail():
if (is.fail())
// Failed to read!
An opening mode can be provided as second parameter to the constructor of a file stream or to its open() member
function:
std::ifstream is;
is.open("foo.txt", std::ios::in | std::ios::binary);
It is to be noted that you have to set ios::in or ios::out if you want to set other flags as they are not implicitly set
by the iostream members although they have a correct default value.
If you don't specify an opening mode, then the following default modes are used:
ifstream - in
ofstream - out
fstream - in and out
The file opening modes that you may specify by design are:
Note: Setting the binary mode lets the data be read/written exactly as-is; not setting it enables the translation of
the newline '\n' character to/from a platform specific end of line sequence.
if (f)
{
std::stringstream buffer;
buffer << f.rdbuf();
f.close();
The rdbuf() method returns a pointer to a streambuf that can be pushed into buffer via the
stringstream::operator<< member function.
std::ifstream f("file.txt");
if (f)
{
std::string str((std::istreambuf_iterator<char>(f)),
std::istreambuf_iterator<char>());
// Operations on `str`...
}
This is nice because requires little code (and allows reading a file directly into any STL container, not only strings)
but can be slow for big files.
NOTE: the extra parentheses around the first argument to the string constructor are essential to prevent the most
vexing parse problem.
std::ifstream f("file.txt");
if (f)
{
f.seekg(0, std::ios::end);
const auto size = f.tellg();
// Operations on `str`...
}
You should always apply a local to a stream before opening the file.
Once the stream has been imbued you should not change the locale.
Reasons for Restrictions: Imbuing a file stream with a locale has undefined behavior if the current locale is not
state independent or not pointing at the beginning of the file.
UTF-8 streams (and others) are not state independent. Also a file stream with a UTF-8 locale may try and read the
BOM marker from the file when it is opened; so just opening the file may read characters from the file and it will
not be at the beginning.
#include <iostream>
#include <fstream>
#include <locale>
int main()
{
std::cout << "User-preferred locale setting is "
<< std::locale("").name().c_str() << std::endl;
Explicitly switching to the classic "C" locale is useful if your program uses a different default locale and you want to
ensure a fixed standard for reading and writing files. With a "C" preferred locale, the example writes
If, for example, the preferred locale is German and hence uses a different number format, the example writes
78 123,456
78,123.456
78123.456
while (!f.eof())
{
// Everything is OK
f >> buffer;
/* Use `buffer` */
}
while (!f.eof())
{
f >> buffer >> std::ws;
if (f.fail())
break;
/* Use `buffer` */
}
but
Further references:
std::ofstream os("foo.txt");
os << "Hello World!" << std::flush;
There is a stream manipulator std::endl that combines writing a newline with flushing the stream:
Buffering can improve the performance of writing to a stream. Therefore, applications that do a lot of writing
should avoid flushing unnecessarily. Contrary, if I/O is done infrequently, applications should consider flushing
frequently in order to avoid data getting stuck in the stream object.
std::ifstream file("file3.txt");
std::vector<std::string> v;
std::string s;
while(file >> s) // keep reading until we run out
{
v.push_back(s);
}
In the above example we are simply iterating through the file reading one "item" at a time using operator>>. This
same affect can be achieved using the std::istream_iterator which is an input iterator that reads one "item" at a
time from the stream. Also most containers can be constructed using two iterators so we can simplify the above
code to:
std::ifstream file("file3.txt");
std::vector<std::string> v(std::istream_iterator<std::string>{file},
std::istream_iterator<std::string>{});
We can extend this to read any object types we like by simply specifying the object we want to read as the template
parameter to the std::istream_iterator. Thus we can simply extend the above to read lines (rather than words)
like this:
std::ifstream file("file3.txt");
With C++17 the standard way to copy a file is including the <filesystem> header and using copy_file:
std::fileystem::copy_file("source_filename", "dest_filename");
The filesystem library was originally developed as boost.filesystem and finally merged to ISO C++ as of C++17.
// Write data.
output << prepared_data;
} // The ofstream will go out of scope here.
// Its destructor will take care of closing the file properly.
Calling close() explicitly is only necessary if you want to reuse the same fstream object later, but don't want to
keep the file open in between:
// Preparing data might take a long time. Therefore, we don't open the output file stream
// before we actually can write some data to it.
std::string const more_prepared_data = prepare_complex_data();
// Open the file "foo.txt" for the second time once we are ready for writing.
output.open("foo.txt");
void func4()
{
auto file = std::ifstream("file4.txt");
std::vector<info_type> v;
for(info_type info; file >> info;) // keep reading until we run out
{
// we only get here if the read succeeded
v.push_back(info);
}
Wogger Wabbit
2
6.2
Bilbo Baggins
111
81.3
Mary Poppins
29
154.8
Output:
The class and struct keywords, called class keys, are largely interchangeable, except that the default access
specifier for members and bases is "private" for a class declared with the class key and "public" for a class declared
with the struct or union key (cf. Access modifiers).
struct Vector
{
int x;
int y;
int z;
};
// are equivalent to
class Vector
{
public:
int x;
int y;
int z;
};
By declaring a class` a new type is added to your program, and it is possible to instantiate objects of that class by
Vector my_vector;
my_vector.x = 10;
my_vector.y = my_vector.x + 1; // my_vector.y = 11;
my_vector.z = my_vector.y - 4; // my:vector.z = 7;
Deriving a class may be forbidden with final specifier. Let's declare a final class:
class A final {
};
class A {
};
// OK.
class B final : public A {
};
Keyword Description
public Everyone has access
protected Only the class itself, derived classes and friends have access
private Only the class itself and friends have access
When the type is defined using the class keyword, the default access specifier is private, but if the type is defined
using the struct keyword, the default access specifier is public:
MyStruct s;
s.x = 9; // well formed, because x is public
MyClass c;
c.x = 9; // ill-formed, because x is private
Access specifiers are mostly used to limit access to internal fields and methods, and force the programmer to use a
specific interface, for example to force use of getters and setters instead of referencing a variable directly:
class MyClass {
public: /* Methods: */
private: /* Fields: */
int m_x;
};
Using protected is useful for allowing certain functionality of the type to be only accessible to the derived classes,
for example, in the following code, the method calculateValue() is only accessible to classes deriving from the
struct Plus2Base {
int value() noexcept { return calculateValue() + 2; }
protected: /* Methods: */
virtual int calculateValue() noexcept = 0;
};
struct FortyTwo: Plus2Base {
protected: /* Methods: */
int calculateValue() noexcept final override { return 40; }
};
Note that the friend keyword can be used to add access exceptions to functions or types for accessing protected
and private members.
The public, protected, and private keywords can also be used to grant or limit access to base class subobjects.
See the Inheritance example.
If a class/struct B inherits from a class/struct A, this means that B has as a parent A. We say that B is a derived
class/struct from A, and A is the base class/struct.
struct A
{
public:
int p1;
protected:
int p2;
private:
int p3;
};
public
private
protected
Note that the default inheritance is the same as the default visibility of members: public if you use the struct
keyword, and private for the class keyword.
It's even possible to have a class derive from a struct (or vice versa). In this case, the default inheritance is
controlled by the child, so a struct that derives from a class will default to public inheritance, and a class that
derives from a struct will have private inheritance by default.
public inheritance:
B b;
b.p1 = 1; //well formed, p1 is public
b.p2 = 1; //ill formed, p2 is protected
b.p3 = 1; //ill formed, p3 is inaccessible
private inheritance:
struct B : private A
{
void foo()
{
p1 = 0; //well formed, p1 is private in B
p2 = 0; //well formed, p2 is private in B
p3 = 0; //ill formed, p3 is private in A
}
};
B b;
b.p1 = 1; //ill formed, p1 is private
b.p2 = 1; //ill formed, p2 is private
b.p3 = 1; //ill formed, p3 is inaccessible
protected inheritance:
struct B : protected A
{
void foo()
{
p1 = 0; //well formed, p1 is protected in B
p2 = 0; //well formed, p2 is protected in B
p3 = 0; //ill formed, p3 is private in A
}
};
B b;
b.p1 = 1; //ill formed, p1 is protected
b.p2 = 1; //ill formed, p2 is protected
b.p3 = 1; //ill formed, p3 is inaccessible
Note that although protected inheritance is allowed, the actual use of it is rare. One instance of how protected
inheritance is used in application is in partial base class specialization (usually referred to as "controlled
polymorphism").
When OOP was relatively new, (public) inheritance was frequently said to model an "IS-A" relationship. That is,
public inheritance is correct only if an instance of the derived class is also an instance of the base class.
This was later refined into the Liskov Substitution Principle: public inheritance should only be used when/if an
instance of the derived class can be substituted for an instance of the base class under any possible circumstance
(and still make sense).
Private inheritance is typically said to embody a completely different relationship: "is implemented in terms of"
Protected inheritance is almost never used, and there's no general agreement on what sort of relationship it
embodies.
class Animal{
private:
double weight;
double height;
public:
friend void printWeight(Animal animal);
friend class AnimalPrinter;
// A common use for a friend function is to overload the operator<< for streaming.
friend std::ostream& operator<<(std::ostream& os, Animal animal);
};
class AnimalPrinter
{
public:
void print(const Animal& animal)
{
// Because of the `friend class AnimalPrinter;" declaration, we are
// allowed to access private members here.
std::cout << animal.weight << ", " << animal.height << std::endl;
}
}
int main() {
Animal animal = {10, 5};
printWeight(animal);
AnimalPrinter aPrinter;
aPrinter.print(animal);
10
10, 5
Animal height: 5
struct A{};
struct B: public virtual A{};
When class B has virtual base A it means that A will reside in most derived class of inheritance tree, and thus that
most derived class is also responsible for initializing that virtual base:
struct A
{
int member;
A(int param)
{
member = param;
}
};
struct B: virtual A
{
B(): A(5){}
};
struct C: B
{
C(): /*A(88)*/ {}
};
void f()
{
C object; //error since C is not initializing it's indirect virtual base `A`
}
If we un-comment /*A(88)*/ we won't get any error since C is now initializing it's indirect virtual base A.
Also note that when we're creating variable object, most derived class is C, so C is responsible for creating(calling
constructor of) A and thus value of A::member is 88, not 5 (as it would be if we were creating object of type B).
A A A
/ \ | |
B C B C
\ / \ /
D D
virtual inheritance normal inheritance
B and C both inherit from A, and D inherits from B and C, so there are 2 instances of A in D! This results in ambiguity
when you're accessing member of A through D, as the compiler has no way of knowing from which class do you
want to access that member (the one which B inherits, or the one that is inherited byC?).
Virtual inheritance solves this problem: Since virtual base resides only in most derived object, there will be only one
instance of A in D.
struct A
{
void foo() {}
class A {
public:
int move();
int turn();
};
class B : private A {
public:
using A::turn;
};
B b;
b.move(); // compile error
b.turn(); // OK
This approach efficiently prevents an access to the A public methods by casting to the A pointer or reference:
B b;
A& a = static_cast<A&>(b); // compile error
In the case of public inheritance such casting will provide access to all the A public methods despite on alternative
ways to prevent this in derived B, like hiding:
class B : public A {
private:
int move();
};
or private using:
class B : public A {
private:
using A::move;
};
B b;
struct SomeStruct {
int a;
int b;
void foo() {}
};
SomeStruct var;
// Accessing member variable a in var.
std::cout << var.a << std::endl;
// Assigning member variable b in var.
var.b = 1;
// Calling a member function.
var.foo();
When accessing the members of a class via a pointer, the -> operator is commonly used. Alternatively, the instance
can be dereferenced and the . operator used, although this is less common:
struct SomeStruct {
int a;
int b;
void foo() {}
};
SomeStruct var;
SomeStruct *p = &var;
// Accessing member variable a in var via pointer.
std::cout << p->a << std::endl;
std::cout << (*p).a << std::endl;
// Assigning member variable b in var via pointer.
p->b = 1;
(*p).b = 1;
// Calling a member function via a pointer.
p->foo();
(*p).foo();
When accessing static class members, the :: operator is used, but on the name of the class instead of an instance
of it. Alternatively, the static member can be accessed from an instance or a pointer to an instance using the . or ->
operator, respectively, with the same syntax as accessing non-static members.
struct SomeStruct {
int a;
int b;
void foo() {}
static int c;
static void bar() {}
};
int SomeStruct::c;
SomeStruct var;
SomeStruct* p = &var;
// Assigning static member variable c in struct SomeStruct.
Background
The -> operator is needed because the member access operator . has precedence over the dereferencing operator
*.
One would expect that *p.a would dereference p (resulting in a reference to the object p is pointing to) and then
accessing its member a. But in fact, it tries to access the member a of p and then dereference it. I.e. *p.a is
equivalent to *(p.a). In the example above, this would result in a compiler error because of two facts: First, p is a
pointer and does not have a member a. Second, a is an integer and, thus, can't be dereferenced.
The uncommonly used solution to this problem would be to explicitly control the precedence: (*p).a
Instead, the -> operator is almost always used. It is a short-hand for first dereferencing the pointer and then
accessing it. I.e. (*p).a is exactly the same as p->a.
The :: operator is the scope operator, used in the same manner as accessing a member of a namespace. This is
because a static class member is considered to be in that class' scope, but isn't considered a member of instances
of that class. The use of normal . and -> is also allowed for static members, despite them not being instance
members, for historical reasons; this is of use for writing generic code in templates, as the caller doesn't need to be
concerned with whether a given member function is static or non-static.
struct IHaveATypedef {
typedef int MyTypedef;
};
struct IHaveATemplateTypedef {
template<typename T>
using MyTemplateTypedef = std::vector<T>;
};
Like static members, these typedefs are accessed using the scope operator, ::.
IHaveATypedef::MyTypedef i = 5; // i is an int.
IHaveATemplateTypedef::MyTemplateTypedef<int> v; // v is a std::vector<int>.
As with normal type aliases, each member type alias is allowed to refer to any type defined or aliased before, but
not after, its definition. Likewise, a typedef outside the class definition can refer to any accessible typedefs within
the class definition, provided it comes after the class definition.
template<typename T>
struct Helper {
T get() const { return static_cast<T>(42); }
struct IHaveTypedefs {
// typedef MyTypedef NonLinearTypedef; // Error if uncommented.
typedef int MyTypedef;
typedef Helper<MyTypedef> MyTypedefHelper;
};
Member type aliases can be declared with any access level, and will respect the appropriate access modifier.
class TypedefAccessLevels {
typedef int PrvInt;
protected:
typedef int ProInt;
public:
typedef int PubInt;
};
This can be used to provide a level of abstraction, allowing a class' designer to change its internal workings without
breaking code that relies on it.
class Something {
friend class SomeComplexType;
short s;
// ...
public:
typedef SomeComplexType MyHelper;
// ...
};
// ...
Something s;
Something::MyHelper hlp = s.get_helper();
In this situation, if the helper class is changed from SomeComplexType to some other type, only the typedef and the
friend declaration would need to be modified; as long as the helper class provides the same functionality, any code
class SomethingElse {
AnotherComplexType<bool, int, SomeThirdClass> helper;
public:
typedef decltype(helper) MyHelper;
private:
InternalVariable<MyHelper> ivh;
// ...
public:
MyHelper& get_helper() const { return helper; }
// ...
};
In this situation, changing the implementation of SomethingElse::helper will automatically change the typedef for
us, due to decltype. This minimises the number of modifications necessary when we want to change helper, which
minimises the risk of human error.
As with everything, however, this can be taken too far. If the typename is only used once or twice internally and
zero times externally, for example, there's no need to provide an alias for it. If it's used hundreds or thousands of
times throughout a project, or if it has a long enough name, then it can be useful to provide it as a typedef instead
of always using it in absolute terms. One must balance forwards compatibility and convenience with the amount of
unnecessary noise created.
This can also be used with template classes, to provide access to the template parameters from outside the class.
template<typename T>
class SomeClass {
// ...
public:
typedef T MyParam;
MyParam getParam() { return static_cast<T>(42); }
};
template<typename T>
typename T::MyParam some_func(T& t) {
return t.getParam();
}
SomeClass<int> si;
int i = some_func(si);
This is commonly used with containers, which will usually provide their element type, and other helper types, as
member type aliases. Most of the containers in the C++ standard library, for example, provide the following 12
helper types, along with any other special types they might need.
template<typename T>
class SomeContainer {
public:
// Let's provide the same helper types as most standard containers.
typedef T value_type;
typedef std::allocator<value_type> allocator_type;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef MyIterator<value_type> iterator;
typedef MyConstIterator<value_type> const_iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
};
Prior to C++11, it was also commonly used to provide a "template typedef" of sorts, as the feature wasn't yet
available; these have become a bit less common with the introduction of alias templates, but are still useful in some
situations (and are combined with alias templates in other situations, which can be very useful for obtaining
individual components of a complex type such as a function pointer). They commonly use the name type for their
type alias.
template<typename T>
struct TemplateTypedef {
typedef T type;
}
TemplateTypedef<int>::type i; // i is an int.
This was often used with types with multiple template parameters, to provide an alias that defines one or more of
the parameters.
template<typename T>
struct MonoDisplayLine {
typedef Array<T, 80, 1> type;
};
struct Outer {
struct Inner { };
};
From outside of the enclosing class, nested classes are accessed using the scope operator. From inside the
enclosing class, however, nested classes can be used without qualifiers:
struct Outer {
struct Inner { };
Inner in;
};
// ...
Outer o;
Outer::Inner i = o.in;
As with a non-nested class/struct, member functions and static variables can be defined either within a nested
class, or in the enclosing namespace. However, they cannot be defined within the enclosing class, due to it being
considered to be a different class than the nested class.
// Bad.
struct Outer {
struct Inner {
void do_something();
};
void Inner::do_something() {}
};
// Good.
struct Outer {
struct Inner {
void do_something();
};
};
void Outer::Inner::do_something() {}
As with non-nested classes, nested classes can be forward declared and defined later, provided they are defined
before being used directly.
class Outer {
class Inner1;
class Inner2;
Inner1 in1;
Inner2* in2p;
public:
Outer();
Prior to C++11, nested classes only had access to type names, static members, and enumerators from the
enclosing class; all other members defined in the enclosing class were off-limits.
Version ≥ C++11
As of C++11, nested classes, and members thereof, are treated as if they were friends of the enclosing class, and
can access all of its members, according to the usual access rules; if members of the nested class require the ability
to evaluate one or more non-static members of the enclosing class, they must therefore be passed an instance:
class Outer {
struct Inner {
int get_sizeof_x() {
return sizeof(x); // Legal (C++11): x is unevaluated, so no instance is required.
}
int get_x() {
return x; // Illegal: Can't access non-static member without an instance.
}
int get_x(Outer& o) {
return o.x; // Legal (C++11): As a member of Outer, Inner can access private members.
}
};
int x;
};
Conversely, the enclosing class is not treated as a friend of the nested class, and thus cannot access its private
members without explicitly being granted permission.
class Outer {
class Inner {
// friend class Outer;
int x;
};
Inner in;
public:
int get_x() {
return in.x; // Error: int Outer::Inner::x is private.
// Uncomment "friend" line above to fix.
}
};
Friends of a nested class are not automatically considered friends of the enclosing class; if they need to be friends
of the enclosing class as well, this must be declared separately. Conversely, as the enclosing class is not
class Outer {
friend void barge_out(Outer& out, Inner& in);
class Inner {
friend void barge_in(Outer& out, Inner& in);
int i;
};
int o;
};
As with all other class members, nested classes can only be named from outside the class if they have public
access. However, you are allowed to access them regardless of access modifier, as long as you don't explicitly name
them.
class Outer {
struct Inner {
void func() { std::cout << "I have no private taboo.\n"; }
};
public:
static Inner make_Inner() { return Inner(); }
};
// ...
You can also create a type alias for a nested class. If a type alias is contained in the enclosing class, the nested type
and the type alias can have different access modifiers. If the type alias is outside the enclosing class, it requires that
either the nested class, or a typedef thereof, be public.
class Outer {
class Inner_ {};
public:
typedef Inner_ Inner;
};
As with other classes, nested classes can both derive from or be derived from by other classes.
struct Outer {
struct Inner : Base {};
};
This can be useful in situations where the enclosing class is derived from by another class, by allowing the
programmer to update the nested class as necessary. This can be combined with a typedef to provide a consistent
name for each enclosing class' nested class:
class BaseOuter {
struct BaseInner_ {
virtual void do_something() {}
virtual void do_something_else();
} b_in;
public:
typedef BaseInner_ Inner;
void BaseOuter::BaseInner_::do_something_else() {}
// ---
public:
typedef DerivedInner_ Inner;
void DerivedOuter::DerivedInner_::do_something_else() {}
// ...
// Calls BaseOuter::BaseInner_::do_something();
BaseOuter* b = new BaseOuter;
BaseOuter::Inner& bin = b->getInner();
bin.do_something();
b->getInner().do_something();
In the above case, both BaseOuter and DerivedOuter supply the member type Inner, as BaseInner_ and
DerivedInner_, respectively. This allows nested types to be derived without breaking the enclosing class' interface,
and allows the nested type to be used polymorphically.
void foo()
{
struct /* No name */ {
float x;
float y;
} point;
point.x = 42;
}
or
struct Circle
{
struct /* No name */ {
float x;
float y;
} center; // but a member name
float radius;
};
and later
Circle circle;
circle.center.x = 42.f;
struct InvalidCircle
{
struct /* No name */ {
float centerX;
float centerY;
}; // No member either.
float radius;
};
Version ≥ C++11
decltype(circle.point) otherPoint;
void print_square_coordinates()
{
const struct {float x; float y;} points[] = {
{-1, -1}, {-1, 1}, {1, -1}, {1, 1}
};
class Example {
static int num_instances; // Static data member (static member variable).
int i; // Non-static member variable.
public:
static std::string static_str; // Static data member (static member variable).
static int static_func(); // Static member function.
int Example::num_instances;
std::string Example::static_str = "Hello.";
// ...
class Example {
static int num_instances; // Declaration.
public:
static std::string static_str; // Declaration.
// ...
};
Due to this, static variables can be incomplete types (apart from void), as long as they're later defined as a
complete type.
struct ForwardDeclared;
class ExIncomplete {
static ForwardDeclared fd;
static ExIncomplete i_contain_myself;
static int an_array[];
};
ForwardDeclared ExIncomplete::fd;
ExIncomplete ExIncomplete::i_contain_myself;
int ExIncomplete::an_array[5];
Static member functions can be defined inside or outside the class definition, as with normal member functions. As
with static member variables, the keyword static is omitted when defining static member functions outside the
class definition.
public:
static int static_func() { return num_instances; }
// ...
// Or...
If a static member variable is declared const but not volatile, and is of an integral or enumeration type, it can be
initialised at declaration, inside the class definition.
struct ExConst {
const static int ci = 5; // Good.
static const E ce = VAL; // Good.
const static double cd = 5; // Error.
static const volatile int cvi = 5; // Error.
As of C++11, static member variables of LiteralType types (types that can be constructed at compile time,
according to constexpr rules) can also be declared as constexpr; if so, they must be initialised within the class
definition.
struct ExConstexpr {
constexpr static int ci = 5; // Good.
static constexpr double cd = 5; // Good.
constexpr static int carr[] = { 1, 1, 2 }; // Good.
static constexpr ConstexprConstructibleClass c{}; // Good.
constexpr static int bad_ci; // Error.
};
If a const or constexpr static member variable is odr-used (informally, if it has its address taken or is assigned to a
reference), then it must still have a separate definition, outside the class definition. This definition is not allowed to
contain an initialiser.
struct ExODR {
static const int odr_used = 5;
};
const int* odr_user = & ExODR::odr_used; // Error; uncomment above line to resolve.
As static members aren't tied to a given instance, they can be accessed using the scope operator, ::.
They can also be accessed as if they were normal, non-static members. This is of historical significance, but is used
less commonly than the scope operator to prevent confusion over whether a member is static or non-static.
Example ex;
std::string rts = ex.static_str;
Class members are able to access static members without qualifying their scope, as with non-static class members.
class ExTwo {
static int num_instances;
int my_num;
int ExTwo::num_instances;
They cannot be mutable, nor would they need to be; as they aren't tied to any given instance, whether an instance
is or isn't const doesn't affect static members.
struct ExDontNeedMutable {
int immuta;
mutable int muta;
static int i;
// ...
class ExAccess {
static int prv_int;
protected:
static int pro_int;
public:
static int pub_int;
};
int ExAccess::prv_int;
int ExAccess::pro_int;
int ExAccess::pub_int;
// ...
As they aren't tied to a given instance, static member functions have no this pointer; due to this, they can't access
non-static member variables unless passed an instance.
class ExInstanceRequired {
int i;
public:
ExInstanceRequired() : i(0) {}
Due to not having a this pointer, their addresses can't be stored in pointers-to-member-functions, and are instead
stored in normal pointers-to-functions.
struct ExPointer {
void nsfunc() {}
static void sfunc() {}
};
Due to not having a this pointer, they also cannot be const or volatile, nor can they have ref-qualifiers. They also
cannot be virtual.
struct ExCVQualifiersAndVirtual {
static void func() {} // Good.
static void cfunc() const {} // Error.
static void vfunc() volatile {} // Error.
static void cvfunc() const volatile {} // Error.
static void rfunc() & {} // Error.
static void rvfunc() && {} // Error.
As they aren't tied to a given instance, static member variables are effectively treated as special global variables;
they're created when the program starts, and destroyed when it exits, regardless of whether any instances of the
class actually exist. Only a single copy of each static member variable exists (unless the variable is declared
thread_local (C++11 or later), in which case there's one copy per thread).
Static member variables have the same linkage as the class, whether the class has external or internal linkage. Local
classes and unnamed classes aren't allowed to have static members.
class A {};
class B : public A {};
class A {};
class B {};
class C : public A, public B {};
Note: this can lead to ambiguity if the same names are used in multiple inherited classs or structs. Be careful!
Multiple inheritance may be helpful in certain cases but, sometimes odd sort of problem encounters while using
multiple inheritance.
For example: Two base classes have functions with same name which is not overridden in derived class and if you
write code to access that function using object of derived class, compiler shows error because, it cannot determine
which function to call. Here is a code for this type of ambiguity in multiple inheritance.
class base1
{
public:
void funtion( )
{ //code for base1 function }
};
class base2
{
void function( )
{ // code for base2 function }
};
};
int main()
{
derived obj;
But, this problem can be solved using scope resolution function to specify which function to class either base1 or
base2:
int main()
{
obj.base1::function( ); // Function of class base1 is called.
obj.base2::function( ); // Function of class base2 is called.
}
class CL {
public:
void member_function() {}
};
CL instance;
instance.member_function();
struct ST {
void defined_inside() {}
void defined_outside();
};
void ST::defined_outside() {}
They can be CV-qualified and/or ref-qualified, affecting how they see the instance they're called upon; the function
will see the instance as having the specified cv-qualifier(s), if any. Which version is called will be based on the
instance's cv-qualifiers. If there is no version with the same cv-qualifiers as the instance, then a more-cv-qualified
version will be called if available.
struct CVQualifiers {
void func() {} // 1: Instance is non-cv-qualified.
void func() const {} // 2: Instance is const.
CVQualifiers non_cv_instance;
const CVQualifiers c_instance;
Member function ref-qualifiers indicate whether or not the function is intended to be called on rvalue instances,
and use the same syntax as function cv-qualifiers.
struct RefQualifiers {
void func() & {} // 1: Called on normal instances.
void func() && {} // 2: Called on rvalue (temporary) instances.
};
RefQualifiers rf;
rf.func(); // Calls #1.
RefQualifiers{}.func(); // Calls #2.
struct BothCVAndRef {
void func() const& {} // Called on normal instances. Sees instance as const.
void func() && {} // Called on temporary instances.
};
They can also be virtual; this is fundamental to polymorphism, and allows a child class(es) to provide the same
interface as the parent class, while supplying their own functionality.
struct Base {
virtual void func() {}
};
struct Derived {
virtual void func() {}
A std::unique_ptr is a class template that manages the lifetime of a dynamically stored object. Unlike for
std::shared_ptr, the dynamic object is owned by only one instance of a std::unique_ptr at any time,
Only the variable ptr holds a pointer to a dynamically allocated int. When a unique pointer that owns an object
goes out of scope, the owned object is deleted, i.e. its destructor is called if the object is of class type, and the
memory for that object is released.
To use std::unique_ptr and std::make_unique with array-types, use their array specializations:
You can access the std::unique_ptr just like a raw pointer, because it overloads those operators.
You can transfer ownership of the contents of a smart pointer to another pointer by using std::move, which will
cause the original smart pointer to point to nullptr.
// 1. std::unique_ptr
std::unique_ptr<int> ptr = std::make_unique<int>();
// Change value to 1
*ptr = 1;
// 2. std::unique_ptr (by moving 'ptr' to 'ptr2', 'ptr' doesn't own the object anymore)
std::unique_ptr<int> ptr2 = std::move(ptr);
Returning unique_ptr from functions. This is the preferred C++11 way of writing factory functions, as it clearly
conveys the ownership semantics of the return: the caller owns the resulting unique_ptr and is responsible for it.
int* foo_cpp03();
The class template make_unique is provided since C++14. It's easy to add it manually to C++11 code:
Unlike the dumb smart pointer (std::auto_ptr), unique_ptr can also be instantiated with vector allocation (not
std::vector). Earlier examples were for scalar allocations. For example to have a dynamically allocated integer
array for 10 elements, you would specify int[] as the template type (and not just int):
You need not to worry about de-allocation. This template specialized version calls constructors and destructors
appropriately. Using vectored version of unique_ptr or a vector itself - is a personal choice.
In versions prior to C++11, std::auto_ptr was available. Unlike unique_ptr it is allowed to copy auto_ptrs, upon
which the source ptr will lose the ownership of the contained pointer and the target receives it.
To create multiple smart pointers that share the same object, we need to create another shared_ptr that aliases
the first shared pointer. Here are 2 ways of doing it:
Either of the above ways makes secondShared a shared pointer that shares ownership of our instance of Foo with
firstShared.
The smart pointer works just like a raw pointer. This means, you can use * to dereference them. The regular ->
operator works as well:
Finally, when the last aliased shared_ptr goes out of scope, the destructor of our Foo instance is called.
Warning: Constructing a shared_ptr might throw a bad_alloc exception when extra data for shared ownership
semantics needs to be allocated. If the constructor is passed a regular pointer it assumes to own the object pointed
to and calls the deleter if an exception is thrown. This means shared_ptr<T>(new T(args)) will not leak a T object if
allocation of shared_ptr<T> fails. However, it is advisable to use make_shared<T>(args) or
allocate_shared<T>(alloc, args), which enable the implementation to optimize the memory allocation.
Specifying std::default_delete is mandatory here to make sure that the allocated memory is correctly cleaned up
using delete[].
template<class Arr>
struct shared_array_maker {};
template<class T, std::size_t N>
struct shared_array_maker<T[N]> {
std::shared_ptr<T> operator()const{
auto r = std::make_shared<std::array<T,N>>();
if (!r) return {};
return {r.data(), r};
}
Version ≥ C++17
With C++17, shared_ptr gained special support for array types. It is no longer necessary to specify the array-deleter
explicitly, and the shared pointer can be dereferenced using the [] array index operator:
Both p2 and p1 own the object of type Foo, but p2 points to its int member x. This means that if p1 goes out of
scope or is reassigned, the underlying Foo object will still be alive, ensuring that p2 does not dangle.
Important: A shared_ptr only knows about itself and all other shared_ptr that were created with the alias
constructor. It does not know about any other pointers, including all other shared_ptrs created with a reference to
the same Foo instance:
By default, shared_ptr increments the reference count and doesn't transfer the ownership. However, it can be
made to transfer the ownership using std::move:
shared_ptr<int> up = make_shared<int>();
// Transferring the ownership
shared_ptr<int> up2 = move(up);
// At this point, the reference count of up = 0 and the
// ownership of the pointer is solely with up2 with reference count = 1
#include <memory>
#include <vector>
struct TreeNode {
std::weak_ptr<TreeNode> parent;
std::vector< std::shared_ptr<TreeNode> > children;
};
int main() {
// Create a TreeNode to serve as the root/parent.
std::shared_ptr<TreeNode> root(new TreeNode);
// Reset the root shared pointer, destroying the root object, and
// subsequently its child nodes.
root.reset();
}
As child nodes are added to the root node's children, their std::weak_ptr member parent is set to the root node.
The member parent is declared as a weak pointer as opposed to a shared pointer such that the root node's
reference count is not incremented. When the root node is reset at the end of main(), the root is destroyed. Since
the only remaining std::shared_ptr references to the child nodes were contained in the root's collection children,
all child nodes are subsequently destroyed as well.
Due to control block implementation details, shared_ptr allocated memory may not be released until shared_ptr
reference counter and weak_ptr reference counter both reach zero.
#include <memory>
int main()
{
{
std::weak_ptr<int> wk;
{
// std::make_shared is optimized by allocating only once
// while std::shared_ptr<int>(new int(42)) allocates twice.
// Drawback of std::make_shared is that control block is tied to our integer
std::shared_ptr<int> sh = std::make_shared<int>(42);
wk = sh;
// sh memory should be released at this point...
}
// ... but wk is still alive and needs access to control block
}
// now memory is released (sh and wk)
}
Since std::weak_ptr does not keep its referenced object alive, direct data access through a std::weak_ptr is not
possible. Instead it provides a lock() member function that attempts to retrieve a std::shared_ptr to the
referenced object:
Instead, you need to define your own deleter. The examples here use the SDL_Surface structure which should be
freed using the SDL_FreeSurface() function, but they should be adaptable to many other C interfaces.
The deleter must be callable with a pointer argument, and therefore can be e.g. a simple function pointer:
Any other callable object will work, too, for example a class with an operator():
struct SurfaceDeleter {
void operator()(SDL_Surface* surf) {
SDL_FreeSurface(surf);
}
};
This not only provides you with safe, zero overhead (if you use unique_ptr) automatic memory management, you
Note that the deleter is part of the type for unique_ptr, and the implementation can use the empty base
optimization to avoid any change in size for empty custom deleters. So while std::unique_ptr<SDL_Surface,
SurfaceDeleter> and std::unique_ptr<SDL_Surface, void(*)(SDL_Surface*)> solve the same problem in a
similar way, the former type is still only the size of a pointer while the latter type has to hold two pointers: both the
SDL_Surface* and the function pointer! When having free function custom deleters, it is preferable to wrap the
function in an empty type.
In cases where reference counting is important, one could use a shared_ptr instead of an unique_ptr. The
shared_ptr always stores a deleter, this erases the type of the deleter, which might be useful in APIs. The
disadvantages of using shared_ptr over unique_ptr include a higher memory cost for storing the deleter and a
performance cost for maintaining the reference count.
With template auto, we can make it even easier to wrap our custom deleters:
Here, the purpose of auto is to handle all free functions, whether they return void (e.g. SDL_FreeSurface) or not
(e.g. fclose).
NOTE: std::auto_ptr has been deprecated in C++11 and will be removed in C++17. You should only use this if you
are forced to use C++03 or earlier and are willing to be careful. It is recommended to move to unique_ptr in
combination with std::move to replace std::auto_ptr behavior.
Before we had std::unique_ptr, before we had move semantics, we had std::auto_ptr. std::auto_ptr provides
unique ownership but transfers ownership upon copy.
As with all smart pointers, std::auto_ptr automatically cleans up resources (see RAII):
std::auto_ptr<X> px = ...;
std::auto_ptr<X> py = px;
// px is now empty
This allows to use std::auto_ptr to keep ownership explicit and unique at the danger of losing ownership
unintended:
void f(std::auto_ptr<X> ) {
// assumes ownership of X
// deletes it at end of scope
};
std::auto_ptr<X> px = ...;
f(px); // f acquires ownership of underlying X
// px is now empty
px->foo(); // NPE!
// px.~auto_ptr() does NOT delete
The transfer of ownership happened in the "copy" constructor. auto_ptr's copy constructor and copy assignment
operator take their operands by non-const reference so that they could be modified. An example implementation
might be:
T* release() {
T* tmp = ptr;
ptr = nullptr;
return tmp;
}
This breaks copy semantics, which require that copying an object leaves you with two equivalent versions of it. For
T a = ...;
T b(a);
assert(b == a);
But for auto_ptr, this is not the case. As a result, it is not safe to put auto_ptrs in containers.
Note that std::reinterpret_pointer_cast is not available in C++11 and C++14, as it was only proposed by N3920
and adopted into Library Fundamentals TS in February 2014. However, it can be implemented as follows:
// Like std::default_delete:
template<class T>
struct default_copier {
// a copier must handle a null T const* in and return null:
T* operator()(T const* tin)const {
if (!tin) return nullptr;
return new T(*tin);
}
void operator()(void* dest, T const* tin)const {
if (!tin) return;
return new(dest) T(*tin);
}
};
// tag class to handle empty case:
struct empty_ptr_t {};
constexpr empty_ptr_t empty_ptr{};
// the value pointer type itself:
template<class T, class Copier=default_copier<T>, class Deleter=std::default_delete<T>,
class Base=std::unique_ptr<T, Deleter>
>
struct value_ptr:Base, private Copier {