General Concepts of C++ Programming Language You Need To Know

C++ General Concepts Techhyme

This article’s content has been a broad overview to give you a feel for some of the general concepts of C++.

  1. A C++ program consists of one or more functions, one of which is called main(). Execution always starts with main().
  2. The executable part of a function is made up of statements contained between braces.
  3. A pair of curly braces is used to enclose a statement block.
  4. A statement is terminated by a semicolon.
  5. Keywords are reserved words that have specific meanings in C++. No entity in your program can have a name that coincides with a keyword.
  6. A C++ program will be contained in one or more files. Source files contain the executable code, and header files contain definitions used by the executable code.
  7. The source files that contain the code defining functions typically have the extension .cpp.
  8. Header files that contain definitions that are used by a source file typically have the extension .h.
  9. Preprocessor directives specify operations to be performed on the code in a file. All preprocessor directives execute before the code in a file is compiled.
  10. The contents of a header file are added into a source file by an #include preprocessor directive.
  11. The Standard Library provides an extensive range of capabilities that supports and extends the C++ language.
  12. Access to Standard Library functions and definitions is enabled through including Standard Library header files in a source file.
  13. Input and output are performed using streams and involve the use of the insertion and extraction operators, << and >>. Std::cin is a standard input stream that corresponds to the keyboard. Std::cout is a standard output stream for writing text to the screen. Both are defined in the iostream Standard Library header.
  14. Object-oriented programming involves defining new data types that are specific to your problem. Once you’ve defined the data types that you need, a program can be written in terms of the new data types.
  15. Unicode defines unique integer code values that represent characters for virtually all of the languages in the world as well as many specialized character sets. Code values are referred to as code points. Unicode also defines how these code points may be encoded as byte sequences.
  16. Constants of any kind are called literals. All literals have a type.
  17. You can define integer literals as decimal, hexadecimal, octal, or binary values.
  18. A floating-point literal must contain a decimal point or an exponent or both. If there is neither, you have specified an integer.
  19. The fundamental types that store integers are short, int, long, and long long. These store signed integers, but you can also use the type modifier unsigned preceding any of these type names to produce a type that occupies the same number of bytes but stores unsigned integers.
  20. The floating-point data types are float, double, and long double.
  21. Uninitialized variables generally contain garbage values. Variables may be given initial values when they’re defined, and it’s good programming practice to do so. A braced initialize is the preferred way of specifying initial values.
  22. A variable of type char can store a single character and occupies one byte. Type char may be signed or unsigned, depending on your compiler. You can also use variables of the types signed char and unsigned char to store integers. Types char, signed char, and unsigned char are different types.
  23. Type wchar_t stores a wide character and occupies either two or four bytes, depending on your compiler. Type’s char16_t and char32_t may be better for handling Unicode characters in a cross-platform manner.
  24. You can fix the value of a variable by using the const modifier. The compiler will check for any attempts within the program source file to modify a variable defined as const.
  25. The four main mathematic operations correspond to the binary +, -, *, and / operators. For integers, the modulus operator % gives you the remainder after integer division.
  26. The ++ and — operators are special shorthand for adding or subtracting one from a numeric variable. Both exist in postfix and prefix forms.
  27. You can mix different types of variables and constants in an expression. The compiler will arrange for one operand in a binary operation to be automatically converted to the type of the other operand when they differ.
  28. The compiler will automatically convert the type of the result of an expression on the right of an assignment to the type of the variable on the left where these are different. This can cause loss of information when the left-side type isn’t able to contain the same information as the right-side type—double converted to int, for example, or long converted to short.
  29. You can explicitly convert a value of one type to another using the static_cast<> () operator.
  30. You don’t need to memorize the operator precedence and associatively for all operators, but you need to be conscious of it when writing code. Always use parentheses if you are unsure about precedence.
  31. The type-safe enumerations type are useful for representing fixed sets of values, especially those that have names, such as days of the week or suits in a pack of playing cards.
  32. The bitwise operators are necessary when you are working with flags -single bits that signify a state. These arise surprisingly often—when dealing with file input and output, for example. The bitwise operators are also essential when you are working with values packed into a single variable. One extremely common example thereof is RGB-like encodings, where three to four components of a given color are packed into one 32-bit integer value.
  33. The using keyword allows you to define aliases for other types. In legacy code, you might still encounter typedef being used for the same purpose.
  34. By default, a variable defined within a block is automatic, which means that it exists only from the point at which it is defined to the end of the block in which its definition appears, as indicated by the closing brace of the block that encloses its definition.
  35. Variables can be defined outside of all the blocks in a program, in which case they have global namespace scope and static storage duration by default. Variables with global scope are accessible from anywhere within the program file that contains them, following the point at which they’re defined, except where a local variable exists with the same name as the global variable. Even then, they can still be reached by using the scope resolution operator (::).
  36. You can compare two values using the comparison operators. This will result in a value of type bool, which can be either true or false.
  37. You can convert a bool value to an integer type true will convert to 1, and false will convert to 0.
  38. Numerical values can be converted to type bool a zero value converts to false, and any nonzero value converts to true. When a numerical value appears where a bool value is expected such as in an if condition the compiler will insert an implicit conversion of the numerical value to type bool.
  39. The if statement executes a statement or a block of statements depending on the value of a condition expression. If the condition is true, the statement or block executes. If the condition is false, it doesn’t.
  40. The if-else statement executes a statement or block of statements when the condition is true and executes another statement or block when the condition is false.
  41. If and if-else statements can be nested.
  42. The logical operators &&, ||, and! Are used to string together more complex logical expressions. The arguments to these operators must either be Booleans or values that are convertible to Booleans (such as integral values).
  43. The conditional operator selects between two values depending on the value of an expression.
  44. The switch statement provides a way to select one from a fixed set of options, depending on the value of an expression of integral or enumeration type.
  45. An array stores a fixed number of values of a given type.
  46. You access elements in a one-dimensional array using an index value between square brackets. Index values start at 0, so in a one-dimensional array, an index is the offset from the first element.
  47. An array can have more than one dimension. Each dimension requires a separate index value to reference an element. Accessing elements in an array with two or more dimensions requires an index between square brackets for each array dimension.
  48. A loop is a mechanism for repeating a block of statements.
  49. There are four kinds of loop that you can use: the while loop, the do-while loop, the for loop, and the range-based for loop.
  50. The while loop repeats for as long as a specified condition is true.
  51. The do-while loop always performs at least one iteration and continues for as long as a specified condition is true.
  52. The for loop is typically used to repeat a given number of times and has three control expressions. The first is an initialization expression, executed once at the beginning of the loop. The second is a loop condition, executed before each iteration, which must evaluate to true for the loop to continue. The third is executed at the end of each iteration and is usually used to increment a loop counter.
  53. The range-based for loop iterates over all elements within a range. An array is a range of elements, and a string is a range of characters. The array and vector containers define a range so you can use the range-based for loop to iterate over the elements they contain.
  54. Any kind of loop may be nested within any other kind of loop to any depth.
  55. Executing a continue statement within a loop skips the remainder of the current iteration and goes straight to the next iteration, as long as the loop control condition allows it.
  56. Executing a break statement within a loop causes an immediate exit from the loop.
  57. A loop defines a scope so that variables declared within a loop are not accessible outside the loop. In particular, variables declared in the initialization expression of a for loop are not accessible outside the loop.
  58. The array container stores a sequence of N elements of type T. An array<> container provides an excellent alternative to using the arrays that are built in to the C++ language.
  59. The vector container stores a sequence of elements of type T that increases dynamically in size as required when you add elements. You use a vector<> container instead of a standard array when the number of elements cannot be determined in advance.
  60. A pointer is a variable that contains an address. A basic pointer is referred to as a raw pointer.
  61. You obtain the address of a variable using the address-of operator, &.
  62. To refer to the value pointed to by a pointer, you use the indirection operator, *. This is also called the dereference operator.
  63. You access a member of an object through a pointer or smart pointer using the indirect member selection operator, ->.
  64. You can add integer values to or subtract integer values from the address stored in a raw pointer. The effect is as though the pointer refers to an array, and the pointer is altered by the number of array elements specified by the integer value. You cannot perform arithmetic with a smart pointer.
  65. The new and new [] operators allocate a block of memory in the free store holding a single variable and an array, respectively and return the address of the memory allocated.
  66. You use the delete or delete [] operator to release a block of memory that you’ve allocated previously using either the new or, respectively, the new [] operator. You don’t need to use these operators when the address of free store memory is stored in a smart pointer.
  67. Low-level dynamic memory manipulation is synonymous for a wide range of serious hazards such as dangling pointers, multiple deallocations, deallocation mismatches, memory leaks, and so on. Our golden rule is therefore this: never use the low-level new/new [] and delete/delete [] operators directly. Containers (and std::vector<> in particular) and smart pointers are nearly always the smarter choice!
  68. A smart pointer is an object that can be used like a raw pointer. A smart pointer, by default, is used only to store free store memory addresses.
  69. There are two commonly used varieties of smart pointers. There can only ever be one type unique_ptr pointer in existence that points to a given object of type T, but there can be multiple shared_ptr objects containing the address of a given object of type T. The object will then be destroyed when there are no shared_ptr objects containing its address.
  70. A reference is an alias for a variable that represents a permanent storage location.
  71. You can use a reference type for the loop variable in a range-based for loop to allow the values of the elements in the range to be modified.
  72. The std::string type stores a character string.
  73. Like std::vector, it is a dynamic array—meaning it will allocate more memory when necessary.
  74. Internally, the terminating null character is still present in the array managed by a std::string object, but only for compatibility with legacy and/or C functions. As a user of std::string, you normally do not need to know that it even exists. All string functionality transparently deals with this legacy character for you.
  75. You can store string objects in an array or, better still, in a sequence container such as a vector.
  76. You can access and modify individual characters in a string object using an index between square brackets. Index values for characters in a string object start at 0.
  77. You can use the + operator to concatenate a string object with a string literal, a character, or another string object.
  78. If you want to concatenate a value of one of the fundamental numeric types, such as for instance an int or a double, you must first convert these numbers into a string. Your easiest—though least flexible—option for this is the std::to_string () function template defined in the string header.
  79. Objects of type string have functions to search, modify, and extract substrings.
  80. The string header offers functions such as std::stoi () and std::stod () to convert strings to values of numeric types such as int and double.
  81. A more powerful option to write numbers to a string, or conversely to read them from a string, is std::string stream. You can use string streams in exactly the same manner as you would std::cout and std::cin.
  82. Objects of type wstring contain strings of characters of type wchar_t.
  83. Objects of type u16string contain strings of characters of type char16_t.
  84. Objects of type u32string contain strings of characters of type char32_t
  85. Functions are self-contained compact units of code with a well-defined purpose. A well-written program consists of a large number of small functions, not a small number of large functions.
  86. A function definition consists of the function header that specifies the function name, the parameters, and the return type, followed by the function body containing the executable code for the function.
  87. A function prototype enables the compiler to process calls to a function even though the function definition has not been processed.
  88. The pass-by-value mechanism for arguments to a function passes copies of the original argument values, so the original argument values are not accessible from within the function.
  89. Passing a pointer to a function allows the function to change the value that is pointed to, even though the pointer itself is passed by value.
  90. Declaring a pointer parameter as const prevents modification of the original value.
  91. You can pass the address of an array to a function as a pointer. If you do, you should generally pass the array’s length along as well.
  92. Specifying a function parameter as a reference avoids the copying that is implicit in the pass-by-value mechanism. A reference parameter that is not modified within a function should be specified as const.
  93. Input parameters should be reference-to-const, except for smaller values such as those of fundamental types. Returning values is preferred over output parameters, except for very large values such as std::array<>.
  94. Specifying default values for function parameters allows arguments to be optionally omitted.
  95. Default values can be combined with std::optional<> to make signatures more self-documenting. std::optional<> can be used for optional return values as well.
  96. Returning a reference from a function allows the function to be used on the left of an assignment operator. Specifying the return type as a reference-to-const prevents this.
  97. The signature of a function is defined by the function name together with the number and types of its parameters.
  98. Overloaded functions are functions with the same name but with different signatures and therefore different parameter lists. Overloaded functions cannot be differentiated by the return type.
  99. A recursive function is a function that calls itself. Implementing an algorithm recursively can result in elegant and concise code. Sometimes, but certainly not always, this is at the expense of execution time when compared to other methods of implementing the same algorithm.
  100. A function template is a parameterized recipe used by the compiler to generate overloaded functions.
  101. The parameters in a function template can be type parameters or nontype parameters. The compiler creates an instance of a function template for each function call that corresponds to a unique set of template parameter arguments.
  102. A function template can be overloaded with other functions or function templates.
  103. Both auto and decltype (auto) can be used to let the compiler deduce the return type of a function. This is particularly powerful in the context of templates because their return type may depend on the value of one or more template type arguments.
  104. Each entity in a translation unit must have only one definition. If multiple definitions are allowed throughout a program, they must still all be identical.
  105. A name can have internal linkage, meaning that the name is accessible throughout a translation unit; external linkage, meaning that the name is accessible from any translation unit; or it can have no linkage, meaning that the name is accessible only in the block in which it is defined.
  106. You use header files to contain definitions and declarations required by your source files. A header file can contain template and type definitions, enumerations, constants, function declarations, inline function and variable definitions, and named namespaces. By convention, header file names use the extension .h.
  107. Your source files will typically contain the definitions for all non-inline functions and variables declared in the corresponding header. A C++ source file usually has the file name extension .cpp.
  108. You insert the contents of a header file into a .cpp file by using an #include directive.
  109. A .cpp file is the basis for a translation unit that is processed by the compiler to generate an object file.
  110. A namespace defines a scope; all names declared within this scope have the namespace name attached to them. All declarations of names that are not in an explicit namespace scope are in the global namespace.
  111. A single namespace can be made up of several separate namespace declarations with the same name.
  112. Identical names that are declared within different namespaces are distinct.
  113. To refer to an identifier that is declared within a namespace from outside the namespace, you need to specify the namespace name and the identifier, separated by the scope resolution operator, ::.
  114. Names declared within a namespace can be used without qualification from inside the namespace.
  115. The preprocessing phase executes directives to transform the source code in a translation unit prior to compilation. When all directives have been processed, the translation unit will only contain C++ code, with no preprocessing directives remaining.
  116. You can use conditional preprocessing directives to ensure that the contents of a header file are never duplicated within a translation unit.
  117. You can use conditional preprocessing directives to control whether trace or other diagnostic debug code is included in your program.
  118. The assert () macro enables you to test logical conditions during execution and issue a message and abort the program if the logical condition is false.
  119. You can use static assert to check type arguments for template parameters in a template instance to ensure that a type argument is consistent with the template definition.
  120. A class provides a way to define your own data types. Classes can represent whatever types of objects your particular problem requires.
  121. A class can contain member variables and member functions. The member functions of a class always have free access to the member variables of the same class.
  122. Objects of a class are created and initialized using member functions called constructors. A constructor is called automatically when an object declaration is encountered. Constructors can be overloaded to provide different ways of initializing an object.
  123. A copy constructor is a constructor for an object that is initialized with an existing object of the same class. The compiler generates a default copy constructor for a class if you don’t define one.
  124. Members of a class can be specified as public, in which case they are freely accessible from any function in a program. Alternatively, they can be specified as private, in which case they may be accessed only by member functions, friend functions of the class, or members of nested classes.
  125. Member variables of a class can be static. Only one instance of each static member variable of a class exists, no matter how many objects of the class are created.
  126. Although static member variables of a class are accessible in a member function of an object, they aren’t part of the object and don’t contribute to its size.
  127. Every non-static member function contains the pointer this, which points to the current object for which the function is called.
  128. Static member functions can be called even if no objects of the class have been created. A static member function of a class doesn’t contain the pointer this.
  129. Const member functions can’t modify the member variables of a class object unless the member variables have been declared as mutable.
  130. Using references to class objects as arguments to function calls can avoid substantial overheads in passing complex objects to a function.
  131. A destructor is a member function that is called for a class object when it is destroyed. If you don’t define a class destructor, the compiler supplies a default destructor.
  132. A nested class is a class that is defined inside another class definition.
  133. You can overload any number of operators within a class to provide class-specific behavior. You should do so only to make code easier to read and write.
  134. Overloaded operators should mimic their built-in counterparts as much as possible. Popular exceptions to this rule are the << and >> operators for Standard Library streams and the + operator to concatenate strings.
  135. Operator functions can be defined as members of a class or as global operator functions. You should use member functions whenever possible. You should resort to global operator functions only if there is no other way or if implicit conversions are desirable for the first operand.
  136. For a unary operator defined as a class member function, the operand is the class object. For a unary operator defined as a global operator function, the operand is the function parameter.
  137. For a binary operator function declared as a member of a class, the left operand is the class object, and the right operand is the function parameter. For a binary operator defined by a global operator function, the first parameter specifies the left operand, and the second parameter specifies the right operand.
  138. Functions that implement the overloading of the += operator can be used in the implementation of the + function. This is true for all op= operators.
  139. To overload the increment or the decrement operator, you need two functions that provide the prefix and postfix form of the operator. The function to implement a postfix operator has an extra parameter of type int that serves only to distinguish the function from the prefix version.
  140. To support customized type conversions, you have the choice between conversion operators or a combination of conversion constructors and assignment operators.
  141. A class may be derived from one or more base classes, in which case the derived class inherits members from all of its bases.
  142. Single inheritance involves deriving a class from a single base class. Multiple inheritances involve deriving a class from two or more base classes.
  143. Access to the inherited members of a derived class is controlled by two factors: the access specified of the member in the base class and the access specified of the base class in the derived class declaration.
  144. A constructor for a derived class is responsible for initializing all members of the class, including the inherited members.
  145. Creation of a derived class object always involves the constructors of all of the direct and indirect base classes, which are called in sequence (from the most base through to the most direct) prior to the execution of the derived class constructor.
  146. A derived class constructor can, and often should, explicitly call constructors for its direct bases in the initialization list for the constructor. If you don’t call one explicitly, the base class’s default constructor is called. A copy constructor in a derived class, for one, should always call the copy constructor of all direct base classes.
  147. A member name declared in a derived class, which is the same as an inherited member name, will hide the inherited member. To access the hidden member, use the scope resolution operator to qualify the member name with its class name.
  148. You can use using not only for type aliases but also to inherit constructors (always with the same access specification as in the base class), to modify the access specifications of other inherited members, or to inherit functions that would otherwise be hidden by a derived class’s function with the same name but different signature.
  149. When a derived class with two or more direct base classes contains two or more inherited sub objects of the same class, the duplication can be prevented by declaring the duplicated class as a virtual base class.
  150. Polymorphism involves calling a (virtual) member function of a class through a pointer or a reference and having the call resolved dynamically. That is, the particular function to be called is determined by the object that is pointed to or referenced when the program is executing.
  151. A function in a base class can be declared as virtual. All occurrences of the function in classes that are derived from the base will then be virtual too.
  152. You should always declare the destructor of classes intended to be used as a base class as virtual (often this can be done in combination with = default). This ensures correct selection of a destructor for dynamically created derived class objects. It suffices to do so for the most base class, but it does not hurt to do it elsewhere either.
  153. You should use the override qualifier with each member function of a derived class that overrides a virtual base class member. This causes the compiler to verify that the functions signatures in the base and derived classes are, and forever remain, the same.
  154. The final qualifier may be used on an individual virtual function override to signal that it may not be overridden any further. If an entire class is specified to be final, no derived classes can be defined for it anymore.
  155. Default argument values for parameters in virtual functions are assigned statically, so if default values for a base version of a virtual function exist, default values specified in a derived class will be ignored for dynamically resolved function calls.
  156. The dynamic cast<> operator is generally used to cast from a pointer-to-apolymorphic-base-class to a pointer-to-a-derived-class. If the pointer does not point to an object of the given derived class type, dynamic cast<> evaluates to nullity. This type check is performed dynamically, at runtime.
  157. A pure virtual function has no definition. A virtual function in a base class can be specified as pure by placing = 0 at the end of the member function declaration.
  158. A class with one or more pure virtual functions is called an abstract class, for which no objects can be created. In any class derived from an abstract class, all the inherited pure virtual functions must be defined. If they’re not, it too becomes an abstract class, and no objects of the class can be created.
  159. Exceptions are objects that are used to signal errors in a program.
  160. Code that may throw exceptions is usually contained within a try block, which enables an exception to be detected and processed within the program.
  161. The code to handle exceptions that may be thrown in a try block is placed in one or more catch blocks that must immediately follow the try block.
  162. A try block, along with its catch blocks, can be nested inside another try block.
  163. A catch block with a parameter of a base class type can catch an exception of a derived class type.
  164. A catch block with the parameter specified as an ellipsis will catch an exception of any type.
  165. If an exception isn’t caught by any catch block, then the std::terminate () function is called, which immediately aborts the program execution.
  166. Every resource, including dynamically allocated memory, should always be acquired and released by an RAII object. This implies that, as a rule, you should normally no longer use the keywords new and delete in modern C++ code.
  167. The Standard Library offers various RAII types you should use consistently; the ones you already know about include std::unique_ptr<>, shared_ptr<>, and vector<>.
  168. The no except specification for a function indicates that the function does not throw exceptions. If a no except function does throw an exception it does not catch, std::terminate () is called.
  169. Even if a destructor does not have an explicit no except specified, the compiler will almost always generate one for you. This implies that you must never allow an exception to leave a destructor; otherwise, std::terminate () will be triggered.
  170. The Standard Library defines a range of standard exception types in the stdexcept header that are derived from the std::exception class that is defined in the exception header.
  171. A class template defines a family of class types.
  172. An instance of a class template is a class definition that is generated by the compiler from the template using a set of template arguments that you specify in your code.
  173. An implicit instantiation of a class template arises out of a definition for an object of a class template type.
  174. An explicit instantiation of a class template defines a class for a given set of arguments for the template parameters.
  175. An argument corresponding to a type parameter in a class template can be a fundamental type, a class type, a pointer type, or a reference type.
  176. The type of a nontype parameter can be an integral or enumeration type, a pointer type, or a reference type.
  177. A partial specialization of a class template defines a new template that is to be used for a specific, restricted subset of the arguments for the original template.
  178. A complete specialization of a class template defines a new type for a specific, complete set of parameter arguments for the original template.
  179. A friend of a class template can be a function, a class, a function template, or a class template.
  180. An ordinary class can declare a class template or a function template as a friend.
  181. An revalue is an expression that typically results in a temporary value; an value is one that results in a more persistent value.
  182. std::move () can be used to convert an value (such as a named variable) into an revalue. Take care, though. Once moved, an object should normally not be used anymore.
  183. An revalue reference type is declared using a double ampersand, &&.
  184. The move constructor and move assignment operator have revalue reference parameters, so these will be called when the argument is a temporary (or any other revalue).
  185. If a function inherently copies one of its inputs, passing this argument by value is preferred, even if this concerns an object of a class type. By doing so, you can cater for both value and revalue inputs with one single function definition.
  186. Automatic variables and function parameters should be returned by value and without adding std::move () to the return statement.
  187. Move members should normally be no except; if not, they risk not being invoked by Standard Library containers and other templates.
  188. The rule of five entails that you either declare all copy members, move members, and the destructor together, or none of them at all. The rule of zero urges you to strive to define none at all. The means to achieve rule of zero compliance you actually already know: always manage dynamic memory and other resources using smart pointers, containers, and other RAII techniques!
  189. A pointer to a function stores the address of a function. A pointer to a function can store the address of any function with the specified return type and number and types of parameters.
  190. You can use a pointer to a function to call the function at the address it contains. You can also pass a pointer to a function as a function argument.
  191. Function objects or factors are objects that behave precisely like a function by overloading the function call operator.
  192. Any number of member variables or functions can be added to a function object, making them far more versatile than plain function pointers. For one, factors can be parameterized with any number of additional local variables.
  193. Function objects are powerful but do require quite some coding to set up. This is where lambda expressions come in; they alleviate the need to define the class for each function object you need.
  194. A lambda expression defines either an anonymous function or a function object. Lambda expressions are typically used to pass a function as an argument to another function.
  195. A lambda expression always begins with a lambda introducer that consists of a pair of square brackets that can be empty.
  196. The lambda introducer can contain a capture clause that specifies which variables in the enclosing scope can be accessed from the body of the lambda expression. Variables can be captured by value or by reference.
  197. There are two default capture clauses: = specifies that all variables in the enclosing scope are to be captured by value, and & specifies that all variables in the enclosing scope are captured by reference.
  198. A capture clause can specify specific variables to be captured by value or by reference.
  199. Variables captured by value will have a local copy created. The copy is not modifiable by default. Adding the mutable keyword following the parameter list allows local copies of variables captured by value to be modified.
  200. You can specify the return type for a lambda expression using the trailing return type syntax. If you don’t specify a return type, the compiler deduces the return type from the first return statement in the body of the lambda.
  201. You can use the std::function<> template type that is defined in the functional header to specify the type of a function parameter that will accept any first-class function as an argument, including a lambda expression. In fact, it allows you to specify a named type for a variable be it a function parameter, member variable, or automatic variable that can hold a lambda closure. This is a feat that would otherwise be very hard as the name of this type is known only to the compiler.
  202. Sequence containers store data in a straightforward user-determined linear order, one element after the other.
  203. Your go-to sequential container should be std::vector<>. The practical use for the other sequential containers in real-life applications, and list<>, forward list<>, and deuce<> in particular, is typically limited.
  204. The three container adapters—std::stack<>, queue<>, and priority queue<>— all encapsulate a sequential container, which they use to implement a limited set of operations that allow you to inject and later take out elements. Their difference mostly lies in the order in which these elements come out again.
  205. Sets are duplicate-free containers and are good at determining whether they contain a given element.
  206. Maps uniquely associate keys with values and allow you to quickly retrieve a value given their keys.
  207. Both sets and maps come in two flavors: ordered and unordered. The former are particularly interesting if you need a sorted view on your data as well; the latter have the potential to be more efficient but may come with the complexity of having to define an effective hash function first.
  208. You and of course the Standard algorithms as well can use iterators to enumerate the elements of any given container, without having to know how this data is actually physically organized.
  209. Iterators in C++ typically make heavy use of operator overloading in order to look and feel like pointers.
  210. The Standard Library offers more than a 100 different algorithms, most in the algorithms header. We made sure that the ones you’ll likely use most often are covered either in the main text or in the following exercises.
  211. All algorithms operate on half-open ranges of iterators, and many accept a first-class callback function. Mostly you’ll call an algorithm with a lambda expression if its default behavior does not suit you.
  212. Algorithms that retrieve a single element from a range (find (), find_if (), min_element(), max_element(), and so on) do so by returning an iterate. The end iterate of the range is then always used to denote “not found.”
  213. Algorithms that produce multiple output elements (copy (), copy if (), and so on) should normally always be used in conjunction with the std::back inserter (), front inserter (), and inserter () utilities provided by the iterate header.
  214. To remove multiple elements from sequence containers, you should use the remove-erase idiom.
  215. You can take advantage of the extensive multiprocessing capabilities of current hardware by passing the std:: execution::par execution policy as the first argument to most algorithms.

Other Useful Resources –

Leave a Reply