This C++ wiki page provides a hierarchical listing of topics about the C++ programming language.
- Overview
Like many programming languages, C++ uses a "variable" to name a memory location which can store some value. A running C++ program executes an assignment statementiX=1;to assign value1into variableiX. But first, each variable has a "type" (its way of using its memory bits to represent its values, such asint) which must be specified by the programmer "defining" that variable within some "scope". Assignment is only one example of a statement; a sequence of statements can be grouped into a code block (written within braces). The execution of that code block can be conditional, depending on the result of testing a "relational expression" (e.g., the equality of two sub-expressions inif (iX + iY == 33) {block}). Generally, a program's execution linearly flows from first statement to last statement, but that program flow can jump around as controlled by loops or by "calling a function". Information can be "passed" into the function (via its "parameters"), and/or returned from the function (by areturn 123;statement). C++ enables object-oriented programming (OOP), where an "object" is an instance of a type whose data is a combination of "data members" (as had already been listed in some "class" definition). That class definition also describes "member functions", whose usage is designed to manipulate a specific instance of those data members (i.e., to manipulate a specific object). - Preprocessing
- Macros
A "preprocessor macro" enables the effect of cut-and-paste of source code, from that macro's definition (in a#definestatement) to anywhere the programmer "expands" that macro. This cutting-and-pasting action could be parameterized. If a macro has been defined to accept a parameter, its expansion is allowed to pass nothingness. A "variadic macro" is written to accept a variable number of macro-parameters. - Tokenization
When your C++ source file is being compiled, one of the first things that happens is your compiler uses its preprocessor to "tokenize" your program. Tokenization would process code likeiA+++iBby splitting it into four tokens (variable identifieriA, then operator++, then operator+, then variable identifieriB). A preprocessor macro is able to use##within its definition, to construct a compilation-token while the macro expands. - Preprocessing Strings
Two adjacent string literals are treated as if they had been concatenated. For a string literal that contains a special character (e.g., a newline), either escape that special character (\n) or use a raw-string-literal. A preprocessor macro can optionally add quotation marks to a macro-parameter while that macro expands. - Compile-time Constants
In C++ syntax, there are some quantities that must be known while your compiler is compiling. In those situations, you could use expression1+2(because the compiler is able to perform arithmetic while it's compiling), but function calling is too complex of an activity to occur during compilation (unless that function's features are radically stripped-down). Use keywordconstexprto mark a stripped-down function that might be "called" during compilation, or a variable which might be "evaluated" during compilation. - Compile-time Assertions
The traditional way to assert the truth of something at compile-time was to use the preprocessor's#error(within some#ifblock). But some compile-time activity happens after the preprocessor has finished, so modern code uses astatic_assert()compile-time assertion. - Conditional-Compilation
The traditional way to conditionally-compile code was to use#ifdefor#if. But the preprocessor cannot reason about types, so modern code sometimes usesif constexprinstead.
- Macros
- Namespace
- Namespace Shortcuts
Anything defined withnamespace NRNamespace {...}will require additional qualification (writing variablegiVarBasNRNamespace::giVarB) unless you have requested to skip that requirement on a case-by-case basis (programmingusing NRNamespace::giVarB;). Or, the qualification requirement could be skipped for an entire namespace all at once. - Nesting
Namespaces can be nested, with the qualification programmed asNROuter::NRInner::giVar. - Splitting across Files
A single namespace's location can be split, possibly across multiple files. - Named and Unnamed
An unnamednamespace {...}is a way to restrict the visibility of a global variable to one single file. If you dislike the name that somebody gave to a namespace,namespace NRNew = NROld;creates your own alias for it.
- Namespace Shortcuts
- Type
- Hungarian Prefixes
C++'s signed integer types aresigned char,short,int, andlong long. On Win32, the sizes of those are 1, 2, 4, and 8 bytes (respectively), but that might be different on other platforms. Each of those types has an unsigned version (e.g.,unsigned intinstead ofint). C++'s floating-point types arefloatanddouble. On Win32, the sizes of those are 4 and 8 bytes (respectively). A popular programming practice is to name your variables using a "Hungarian prefix", where its name's first few letters is an encoding of that type (e.g., variablefVarhas typefloat), but the language makes no such requirement. - Boolean
C++'s primitive boolean type isbool. It has valuestrueandfalse. - Literals
- Financial 1000-Markers
A number like one million cannot be programmed as1,000,000because the comma is used for other purposes. But you can write a numeric literal as1'000'000. - Binary and Hexadecimal
The number thirteen can be written in decimal (13), hexadecimal (0x0D), octal (015), or binary (0B1101). - Custom Literals
You can now define your own custom syntax for literals of the formprefix_suffix. After programmingint operator"" _meter(), you can use123_meterin any situation where you used to program with an ordinary numeral.
- Financial 1000-Markers
- Bitwise Representation
- Ordering of Bytes
All CPUs are either "little-endian" (the least-significant bytes occur first in the internal representation of an integer) or "big-endian" (the opposite order). - Negative Value
The negative value of an integer could be stored as either "2's complement" (-1 viewed asunsigned charis0B11111111) or "1's complement" (it is0B11111110). - Bit Shifting
A value's bits could be shifted leftwards or rightwards with<<or>>operators. - Non-char Byte
Astd::bytevariable is like aunsigned charvariable, except that it can only be used for bitwise operations (not for character nor numeric operations). - Bit Flags
A variable whose type isstd::bitset<5>stores five bits (five flags), which are individually accessed using array-indexing notation.
- Ordering of Bytes
- Max Value
- Overflow
On Win32, the max value that can be stored in aunsigned intvariable is0xFFFF'FFFF. If you further increment that variable, it will "overflow" (wrapping around back to0x0000'0000without error or warning). - INT_MAX
In C, macros likeLONG_MINandLONG_MAXhad been defined to be the smallest and largest values that could be represented in that particular type. C++'s modernization ofINT_MAXisstd::numeric_limits<int>::max().
- Overflow
- Conversion
- Promoting Small Integers
Often, there are no machine-language mathematical operators for integers smaller thanint. Consequently, the compilation result ofbTermA + bTermBwherebTermAandbTermBare bothunsigned charwill "promote" both of these two terms intointbefore doing the addition. - Coercion
A math operation can only be applied to two operands of the same type. If they are not already of the same type, then one of them will need to be "coerced" (if possible, the compiler automatically inserts an implicit type-conversion that changes a value's representation from one type to another). - Casting
A "type cast" is a manually-programmed expression of type-conversion. Traditional C programs wrote casting as(float)iVar. C++ programs write casting asstatic_cast<float>(iVar). When casting from a pointer-to-base-class into a pointer-to-derived-class, usingdynamic_cast<>instead ofstatic_cast<>adds a runtime check which returnsNULLif the pointed-at object wasn't actually an instance of that derived class.
- Promoting Small Integers
- Enumeration
A traditional enumeration was written asenum ERType {ZERO=0, ONE, TWO};, but modern code writes it asenum class ERType {...};. In the modern way, values must be fully-qualified asERType::TWOwhen they are used. - Shortcuts
- Templated typedef
A "type alias" lets you use a new name for an existing type. Traditionally, this was programmed astypedef int INTEGER_VIA_TYPEDEF;. In modern C++, this is programmed asusing INTEGER_VIA_USING = int;. Only the modern syntax can be templated. - From Another Variable
If variableiOtherVarhas already been defined to have typeint, then definitiondecltype(iOtherVar) iVar = 22;is the same as definingint iVar = 22;. Thisdecltype()shortcut can even refer to a full expression. - From Initialization
The compiler can infer a variable's type from its initialization data. So definingauto iVar = 11;is the same as definingint iVar = 11;(because11is aintliteral). - From a return Statement
A compiler can infer a function's return type from itsreturnstatement, by specifying the return type as eitherautoordecltype(auto). - Trailing Return Type
In templated code (using template-parameterT), if you want your compiler to infer a function's return type from an expression that involves a parameter's type, then use this "trailing return type" syntax:auto AddTwo(T x) -> decltype(x+2) { return x+2; }.
- Templated typedef
- Variant
- Any-Variant
A variablexVarwhose type isstd::anycan store values of differing types at different points in time. After assigningxVar = 1.1F;, thatfloatvalue can be accessed bystd::any_cast<float>(xVar);. An uninitialized any-variable will be in a special "no value" state that will be reported byxVar.has_value(). - Templated-Variant
A variablexVarwhose type isstd::variant<int,float,std::string>can store a value that is eitherintorfloatorstd::string(only one of those options at a time). Thus, this templated-variant variable is a modern alternative to a Cunion. After assigningxVar = 9.9F;, you know that the variable is currently storing afloatbecausestd::holds_alternative<float>(xVar)returnstrueandxVar.index()returns1(0-based indexing of type options). Access that value by eitherstd::get<float>(xVar)or bystd::get<1>(xVar). - Optional-Value
A variable whose type isstd::optional<int>is similar to a pointer tointin the sense that its value might bestd::nullopt(similar to a null pointer). In that case, we understand it to semantically mean that the variable "has no meaningful value". Otherwise, anintcan be stored by assignment, and accessed by dereferencing.
- Any-Variant
- RTTI: RunTime Type Information
The C++ standard provides rather little support for RTTI. You can calltypeid(int), which returns aconst std::type_info&that can be equated (using==) or converted into string (using.name()).
- Hungarian Prefixes
- Variables
- Lifetime and Scope
A variable defined outside of all functions will have "static-lifetime" (it will exist throughout your software's entire duration). A variable defined inside some function could also have static-lifetime, but it would need to be marked by thestatickeyword. Otherwise, it would be a transient "local-variable" whose storage will disappear when that function ends. A variable defined inside some function has "local-scope" (it can only be used from within that function, regardless of its lifetime). A variable defined outside of all functions has "global-scope" (it can be used by all subsequent functions). If you mark a globally-scoped variable by thestatickeyword, then it can only be used in this source file. - Initialization
A constant variable (marked by theconstkeyword) must be initialized. If a static-lifetime variable is not manually initialized, then it will be automatically initialized to 0. If a local object variable is not manually initialized, then its default-constructor will construct it. If a local primitive variable is not manually initialized, then its value will be undefined until something gets assigned to it. - Uniform Initialization
There are three different syntax that you could use for initializing a variable: traditional "implicit initialization" (int iVar = 11;), traditional "explicit initialization" (int iVar(11);), and modern "uniform initialization" (int iVar {11};). - Initialize without Constructor
Traditionally, data members were initialized by passing parameters to a custom constructor, which would copy those parameterized values to the data members. In modern C++, you also have the option of just using the default constructor, and specifying those values as an initialization list. The items from that brace-enclosed list will be given to data members based on the order of members within the class definition. - Decomposing-Auto
The statementauto[iDesti,fDesti] = oSource;simultaneously defines two variables (iDestiandfDesti), initializing each of them to some corresponding value from the right-hand-side. The right-hand-side could be astd::tuple<int,float>or it could be an object (whose first data member is aint, and second data member is afloat). - Define at Same Time as Type
Programmers usually define a class (class CRType {...};) separately from using that class' name in an object's definition (a subsequentCRType oObject;statement). However, it is possible to combine these into a single codeline (class CRType {...} oObject;).
- Lifetime and Scope
- Indirection
A "pointer" is a variable whose value is a memory address. IfiVarhas already been defined as aintvariable, definingint* piVar = &iVar;will use the "address-of" operator (&) to obtain the address whereiVarhas been stored in memory — that memory address will get stored in pointer variablepiVar. On the other hand, a "reference" (int& riVar = iVar;) doesn't create any additional storage; instead, it specifies a new name (riVar) which now also refers to that same storage location that already existed foriVar.- Pointers
Evaluating the name of a pointer variable (piVar) produces a memory address. Evaluating the "dereferencing" of that pointer variable (*piVar) produces whatever value had been stored in memory at that memory address. - Typed NULL
The traditionalNULLmacro was really just aintwith value0. This is commonly used as a special value assigned to a pointer variable, having the semantic meaning of "not pointing at anything" (because computers will never try to use their memory at address 0). Modern C++ usesnullptrinstead ofNULL, becausenullptrhas a dedicatedstd::nullptr_ttype. - Arrays
The definitionint piArray[3] = {0, 11, 22};defines an "array" variable. In memory, space is reserved for three integers (contiguously). The array variablepiArrayis equivalent to a pointer which is pointing at the first of those three integers. - Reference Variables
A reference (int& riVar = iVar;) must always be initialized to some kind of existing storage, and the location of that storage cannot be changed. However, the value stored at that location can be changed, so subsequently doingriVar = 99;will causeiVarto now contain99. - Rvalue-References
- Move-Semantics
Traditionally, a class could provide a "copy-constructor"CRType::CRType(const CRType& x) {...}and a "copy-assignment operator"CRType& CRType::operator=(const CRType& x) {...}. These would get used in several situations, such as the definition ofoDestibyCRType oDesti(oSource);(whereoSourcehad already been defined as aCRTypeobject). IfCRTypeis some kind of custom container, then these two functions are usually implemented by deeply copying all contained items, which might be computationally-expensive. In modern software, these are supplemented by also programming "move-constructor" and "move-assignment operator" functions that are implemented by only transferring a payload handle. Function overloading can distinguish between move-constructor and copy-constructor, because the move-constructor parameter's type is a "rvalue-reference"CRType&&. - Moving from this
A function likeAssignTo()is the opposite of a common assignment operator (assigning from this object to the parameter, instead of from the parameter to this object). To specify function overloading that distinguishes between move-semantics and copy-semantics, a function likeAssignTo()would program either&or&&immediately before the function body's opening curly-brace. - Perfect Forwarding
If both move-semantics and copy-semantics exist in both a base class and a derived class, then you might need to maintain the choice of move-or-copy when a derived class' function delegates up to the base class' function. To maintain that move-or-copy choice,std::forward<>is used.
- Move-Semantics
- Smart Pointers
- Risk from Raw Pointers
When implementing one of your functions, you might want to dynamically allocate memory (usingCRType* poRaw = new CRType;) which you intend to deallocate at the end of your function (usingdelete poRaw;). But this will leak memory if an unhandled exception gets thrown during the middle of your function. Instead of your local variable's type being a raw pointer, it could be a local object variable (initialized asCRSmart poSmart(new CRType);). WheneverpoSmartgoes out of scope (even if because of an exception), that local object's destructor will get called. So we can move the responsibility of doingdeletefrom our manually-programmed function, into the destructor of thisCRSmart"smart pointer" class. C++ provides several built-in smart pointer classes that work like this. - Unique Ownership
If a smart pointer's memory should be "owned" by exactly one client, usestd::unique_ptr<>for the smart pointer type. - Shared Ownership
Multiplestd::shared_ptr<>variables can collectively manage a shared memory allocation, due to built-in reference-counting. C++ will automatically calldeleteon the underlying memory once all of the smart pointer variables have released their shared-ownership of it. - Ownership Cycle
Thestd::weak_ptr<>type is for situations where you need access to the shared memory payload that is being collectively managed by severalstd::shared_ptr<>, but you don't want thisstd::weak_ptr<>to affect the reference count. A cyclic data structure is one example where that is needed. - Owning an Array
A smart pointer can own an array (e.g.,std::unique_ptr<int[]> piUnique(new int[32]);). When the time comes, it will use the correct destructor (delete[]). - Pointer to Base-Class
The pointer-type managed by a smart pointer can be a base class of the actual memory allocation (i.e.,std::unique_ptr<CRBase> poUnique(new CRDerived);). - Returning this
Traditional C++ code might sometimes have wanted to doreturn this;(returning aCRType*raw pointer). To instead returnstd::shared_ptr<CRType>, derive your class fromstd::enable_shared_from_type<CRType>(so that an internalstd::shared_ptr<>will start owning this object), and returnshared_from_this()instead ofthis. - Smart Compiler-Temporary
C++ creates a compiler-temporary for thenew CRComplex(11,22)portion ofstd::unique_ptr<CRComplex> piVar(new CRComplex(11,22));. To guard against memory leaks from exceptions occuring before that compiler-temporary is given to the smart pointer, usestd::make_unique<CRComplex>(11,22)in place ofnew CRComplex(11,22)(astd::make_unique<>()compiler-temporary is already a smart pointer as soon as it exists). - Custom Destruction
Normally you rely on a smart pointer to decide both "when" and "how" to deallocate. But it is possible for you to provide a custom callable-object for the "how" part. - Template-Parameter
You can access a smart pointer's template-parameter bystd::unique_ptr<int>::element_type.
- Risk from Raw Pointers
- Pointers
- Expressions
- Precedence
C++ follows the standard precedence rule of mathematics, where2 + 3 * 4is parsed the same as if it had been written2 + (3 * 4). Other precedence rules govern all aspects of expression evaluation. - Chain of Assignment
The "compound assignment"iVar += 2;is an abbreviation foriVar = iVar + 2;. Programmers usually think about+=only in terms of its effect (changing the value stored iniVar's memory), but that expression does also evaluate to a value. In fact, it evaluates to a "lvalue" which means thatiVar+=2is allowed to occur on the left-hand-side of some other assignment (although it would be weird to do so).
- Precedence
- Program Flow
C++ does have agotostatement, which alters the program flow by jumping directly to some labelled statement. But, usage ofgotois strongly discouraged.- Loops
- Basic Loops
Loops can be written aswhile (condition) { body }or asdo { body } while(condition);. The initialization and updating of a loop can be consolidated intofor (iIndex = 0; iIndex < 10; iIndex++) { body }. - Looping over a Collection
Any STL collection that provides iterators viabegin()andend()(e.g.,std::vector<int> veciVar = {0,11,22,33};) can be iterated byfor (int iItem : veciVar) { body }.
- Basic Loops
- The break Statement
- A break in a Nested Loop
When there is nesting, abreakstatement only terminates the innermost loop. - Fallthrough in a Switch
Aswitchstatement is an efficient substitute for manyif (x==1) {body} else if (x==5) {body} else if (x=99) {body}chains. In aswitchstatement, each body is a sequence of statements preceded by acase 5:label. If you don't terminate that sequence of statements bybreak;, then program flow will fall-through and also perform the next sequence of statements. This is often a programming bug, so when you intentionally do this, write[[fallthrough]];in place ofbreak;.
- A break in a Nested Loop
- Return Value
It would be unsafe to return a reference to a local variable, but you can return a reference to a data member. - Parameters
- Default Parameter
When defining a function having a parameter, you can specify a default value that will be used if the caller doesn't provide a value for that parameter. For a member function, this should appear in the class definition asvoid DoMember(int aiParam = 123);(use ordinary syntax when implementing this function). - Unused Parameter
Many compilers will warn you if you define a parameter that isn't used anywhere inside your function. If you are doing this intentionally, mark that parameter with[[maybe_unused]]. - Variable Number of Parameters
A parameter's type could bestd::initializer_list<int>. This allows for passing either asDoFunction({11,22,33})or asDoFunction(11,22,33).
- Default Parameter
- Function Overloading
- Discrimination Criteria
"Overloaded" functions are multiple function implementations that all share a common name. They each have their own unique "signature" (the types of the parameters). When an overloaded function is called, the compiler is able to choose which implementation to use, based on the types of values passed to it. However, this overloading cannot discriminate between two implementations based only on return types. - Across Inheritance
Instead of overloading each other, one function hides the other if it is in a derived-class.
- Discrimination Criteria
- Function-Pointer
In traditional C++, a function could be passed-around using "function-pointer" variables. For example, this type alias specifies a pointer to a function that converts a float-pointer into an integer:typedef int (*PTPFTOI)(float*);. - Deprecating a Function
An undesirable part of an API can be marked with[[deprecated]].
- Loops
- Objects
An individual data member of an object is accessed byoObject.m_iMember. The dereference and member-access operators can be combined intopoObject->m_iMember.- Accessibility
In the class definition, you can precede a group of members byprivate:to disallow usage of that member from anywhere outside of that class' own member functions. Or, useprotected:accessibility to also allow access to member functions of derived classes. Thepublic:accessibility allows access from anywhere. - Unwanted Compiler-Generated Functions
The compiler automatically generates several member functions, if the programmer hasn't manually programmed them (e.g., a default constructor). If you want to prevent the compiler from doing that, write that function's signature followed by= delete;. - Constructors
- Ordering
When an object is being instantiated from a class definition, you should usually initialize its data members. Immediately after reserving enough memory to store the object, C++ will automatically call a "constructor" function to perform that data-member-initialization. You implement your constructor as a member function having the same name as the class name, optionally with parameters, having no return type at all. When there's a hierarchy of classes, bass-class-constructors will be called before a derived-class-constructor. - Initialization by Copy-Constructor
"Implicit initialization" (CRType oImp = oCopied;) and "explicit initialization" (CRType oExp(oCopied);) are equivalent in the sense that they both invokeCRType's "copy-constructor". The copy-constructor's signature isCRType::CRType(const CRType& aroCopied). This same copy-constructor will also be called whenever an object is passed-by-value into some function. - Initialization by One-Parameter-Constructor
A one-parameter-constructor is essentially converting the type of some data (from that parameter's type, into this class type). To prevent client code from unintentionally doing this type-conversion when that client uses implicit-initialization syntax, mark this constructor definition with theexplicitkeyword. - Keeping Default Constructor
The compiler provides a do-nothing implementation of the "default constructor" (one that has no parameters), if the programmer hasn't manually provided a custom implementation for it. But traditionally, if the programmer writes any other constructor (having some other overloaded signature of parameters), then this built-in default constructor was not provided by the compiler. If you do write some other constructor, but you still also want the compiler to provide its built-in default constructor, request it withCRType() = default;. - Delegation within Class
With a modern compiler, a constructor could now delegate its implementation to some other constructor of the same class. - Memory Full
The C language'smalloc()returnedNULLif memory was full when that allocation was attempted. C++'sCRType* poObj = new CRType;instead throws astd::bad_allocexception. Alternatively, you could usestd::set_new_handler()to specify a callback that will be repeatedly called until enough memory is available. - Placement New
C++'snewoperator allocates memory, and then executes some constructor within that memory. Low-level software might already have some memory pre-allocated for a new object, only wanting to run its constructor. To do so, call a "placement new" asCRType* poVar = new (preallocation) CRType;.
- Ordering
- Destructors
If a class constructor's implementation has any side-effect (e.g., allocation of memory, or opening of a file), then you usually desire the opposite side-effect to happen whenever that class' instances are going to get destroyed. The compiler knows when it's going to be destroying an object, but the programmer needs to specify that side-effect behavior within a "destructor" function which is written asCRType::~CRType() {body}. - Const Members
- Const Data Members
For data members that are constants or references, you must initialize them in a constructor's "initializer-list", which is written asCRType(int x) : m_iMember(x) {body}. - Const Member Functions
A member function automatically has access to athispointer variable whose type isCRType*and which is automatically pointing at theCRTypeobject being manipulated by this member function. But you could have defined the member function asvoid CRType::DoAction() const {body}, in which case the type ofthisbecomesconst CRType*(that function's body can view data members but not alter them). This restriction can be ignored for individual data members (on a case-by-case basis) but marking the data member withmutable.
- Const Data Members
- Static Members
- Static Data Members
A "static-data-member" is a data member marked by thestatickeyword. It describes one value that is shared by all objects of that class. Generally, a static-data-member must be initialized outside the class definition (by writingint CRType::m_giVar = 11;at the top of some implementation file). - Static Member Functions
Most member functions conceptually manipulate one specific object, but a member function marked by thestatickeyword is for computation that is collectively about all objects of that class. The compiler doesn't provide anythispointer to a static-member-function, so a static-member-function can only access static-data-members. Whereas an ordinary member function is invoked on a specific object (oObject.DoAction()), any code may invoke a static-member-function without having any object (simply callingCRType::DoAction()).
- Static Data Members
- Inheritance
- Polymorphism Syntax
A "derived" class "inherits" all members from its "base" class. A derived class is defined asclass CRDerived : public CRBase {members};. Frequently, an object is allocated by instantiating the derived class, but "pointed-at" by a pointer variable whose type is "pointer-to-base-class":CRBase* poBase = (CRBase*)(new CRDerived);. IfCRBaseandCRDerivedhave provided two different implementations of the sameDoAction()member function, thenpoBase->DoAction()would call the base class' implementation. But if the member function had been marked by thevirtualkeyword, thenpoBase->DoAction()would instead "polymorphically" call the derived class' implementation. - Qualification Syntax
An overriding implementation ofDoAction()can non-polymorphically refer to a base class' implementation as__super::DoAction(). - Restricted Overriding
A library author can use thefinalkeyword to prevent an application programmer from further overriding a virtual-function. An application programmer can use theoverridekeyword to require that the virtual-function he's implementing must have also existed within the base class. - Multiple Inheritance
A C++ class may inherit from multiple base classes. However, that practice is often discouraged unless all but one of the base classes are "interfaces" (in C++, an "interface" takes the form of an "abstract class" having "pure" virtual functions that define an API without providing their own implementations).
- Polymorphism Syntax
- Operator Overloading
Programming custom implementations for operators is the mechanism for allowing a custom C++ class to be used as a "value type" (which then can behave similar to built-in primitive types likeint). For example, client code expects to be able to doint iX = iY + iZ + 9;; if you want your custom class to also behave that way, then define itsconst CRType CRType::operator+(const CRType& aroRhs) {body}. - Nested Classes
An inner class definition may be nested within some outer class definition. The member within that nested class is calledCROuter::CRInner::m_iVar(those qualifications are unnecessary for code within that class' member functions). - Pointer to Members
It is very common to use a type which is "pointer toint" (the type's name isint*). Must less common (but still possible) is using a type which is "pointer tointdata member of classCRType" (the type's name isint CRType::*). - Low-Level C Structures
- Union
Astruct CRType {...};is the same asclass CRType {...};except for default accessibility. Aunion CRType {...};is also the same, except all members in the union overlap in memory (space in memory is made for the largest member). Only one member can have meaningful data at one time. - Flexible-Array-Member
A "flexible-array-member" is a data member which is an array having unspecified size. A flexible-array-member must be the last member, and there must be at least one normal data member before it. - Bitfield
A "bitfield" structure memberintegral_type m_iVar : bit_count;is useful for alignment.
- Union
- Accessibility
- Templates
- Templated-Functions
A templated-function looks like any ordinary function, but with "template-parameter" placeholders for some types:template<typename T> T ComputeMin(T x, T y) { return (x < y) ? x : y; }. No compilation happens here where this templated-function is being defined; instead, thisComputeMin<>()will get compiled (with "specialization"T=intapplied) during the first occurrence of that usage, as inint iResult = ComputeMin<int>(3,4);. In this case, you could have simply writtenint iResult = ComputeMin(3,4);, since the compiler could inferT=intfrom those parameter types. - Templated-Classes
If a class is written as a template, then all of its members share that common abstraction, and are collectively specialized together. - Templated-Variables
Modern C++ can also use template syntax with any global variable (defined outside all functions). Each template-specialization will behave like a separate variable. - Template-Parameters
- Default Template-Parameters
A template-parameter may have a default. That default may be defined in terms of a previous template-parameter:template<typename T0, typename T1 = CRA<T0> > class CRB {...};. - Deducing Template-Parameters
Traditionally, template object initialization needed to explicitly list types:std::pair<float,int> fiVar = std::pair<float,int>(1.1F,2);. Modern C++ compilers can automatically deduce those types:std::pair fiVar = std::pair(1.1F,2);. - Variadic Templates
A "variadic template" has been programmed to specialize a variable number of template-parameters:template<typename T0, typename... TN>.
- Default Template-Parameters
- Traits
- Unary Predicate Traits
A "predicate trait" is a boolean value based on some characteristic of a type. C++ provides many built-in "dummy templates" for a variety of these characteristics (e.g.,std::is_floating_point<int>::valueresolves tofalseat compile-time). - Binary Predicate Traits
Predicate traitstd::is_same<int,__int32>::valuetests those two types for equality (__int32is a platform-specific type on Win32 that is the same asint). - Array Traits
At compile-time,std::rank<int[][8][8]>::valueresolves to3, andstd::extent<int[3][4], 1>::valueresolves to4. - Unary Transform Traits
A "transform trait" specifies a type that is similar to some other type, but with some added (or removed) characteristics. In this example, variablem_iMemberwill be aintdata member for both specializationsT=intandT=int&:template<typename T> class CRClass { std::remove_reference<T>::type m_iMember; };. - Binary Transform Traits
Transform traitstd::common_type<TLHS,TRHS>::typeprovides the coercion-result of a mixed-type-operation. - S.F.I.N.A.E. Conditional Compilation
Modern C++ compilers follow the "Substitution Failure is not an Error" (SFINAE) principle, whereby the compiler silently eliminates a failed specialization from consideration, without that generating a compilation-error.
- Unary Predicate Traits
- Metaprogramming
- Numeric Template-Parameters
A template-parameter usually serves as a placeholder for a type. But, a template-parameter could be numeric. This gives templates a capability of performing compile-time calculations by "template-metaprograms". - Collection of Types
Some template-metafunctions may compute a type (or even a collection of types) as their template-metareturn. For these template-metafunctions, the established convention is to name that resulttype(a nested type alias).
- Numeric Template-Parameters
- Concepts
Traditionally, a templated-function liketemplate<typename T> T Add(T x, T y) { return x + y; }will allow substitution using any type (even types likeT=std::stringthat actually shouldn't be "added together"). You can define a "concept", which is a logical criteria that only some types might satisfy:template<typename T> concept IS_ADDABLE = std::is_arithmetic<T>::value;. Then we can limit allowed substitutions:template<typename T> requires IS_ADDABLE<T> T Add(T x, T y) {...}.
- Templated-Functions
- Error Handling
- Returning an Error Code
When a low-level feature of the operating system needs to report an error, it usually does so by returning an "error code". The Win32 platform has four built-in enumerations of error codes, which the C++ language has combined into a singlestd::error_codetype. - Assertions
Theassert(condition);statement is conditionally-compiled. When building a debug build-configuration, define the_DEBUGpreprocessor symbol so thatassert()will evaluate its condition (aborting the software execution if that condition evaluates tofalse). When building a release build-configuration, instead define theNDEBUGpreprocessor symbol so thatassert()efficiently generates no machine language code. - C++ Exception Handling
If some exceptionally problematic situation might occur in code (either your code or library functions that you call), enclose that code withintry {your code} catch (...) {handler}. When your problem occurs, your code "throws an exception" by doingthrow 99;, and program flow will jump to the handler (even if that requires the C++ langauge to "unwind" a series of called functions). That data (99in this example) is an explanation for what went wrong; it is typed so you could actually program a sequence ofcatch (int aiExplanation) {handler}withcatch (...)meaning "all other types".
- Returning an Error Code
- Standard Libraries
The "Standard Libraries" are an OS-independent set of C++ classes that should be available in any C++ development environment. These classes are within astdnamespace.- C-Runtime
- Math
- Basic Math
The "C-Runtime" is a library that has been carried over from the C language. Its support for basic mathematics includes functions likestd::max(),std::abs(),std::round(), andstd::sqrt(). - Trigonometry
The C-Runtime includes functions likestd::atan2()andstd::exp(). - Rational Numbers
Just as3is a literal form of an integer,std::ratio<-4,3>is a literal form of a rational number. - Complex Numbers
Standard C++ defines a complex number asstd::complex<float> ffVar(3.0F, 4.0F);. Compute its "phase" usingstd::arg(), compute its "magnitude" usingstd::abs(), and compute its "complex conjugate" usingstd::conj(). - Miscellaneous Math
The C-Runtime also provides a variety of miscellaneous math functions, such asstd::fma(2.0F, 3.0F, 4.0F);for computing 2*3+4.
- Basic Math
- Heap Memory
- Allocation
Dynamic memory management with the C-Runtime is done by callingmalloc(), which returns a pointer to the newly-allocated memory. Give that pointer tofree()when you are ready to deallocate that memory. - Memory Manipulation
A whole block of memory can be set by onememset()function call. Thememcpy()function copies a block of memory from one location to another. Two memory blocks can be lexicographically-compared bymemcmp(). A memory block can be searched bymemchr(). - Leaks
Memory "leaks" if you forget to deallocate something that you had dynamically allocated.
- Allocation
- Time
- Time as a String
To specify a date/time, set various data members of astd::tmobject. Callingstd::asctime()converts that information into a string of exactly 26 characters. The computer's current time is obtained bystd::time()as astd::time_tscalar value;std::localtime()converts that scalar value intostd::tm. - Precise Time
The current time obtained bystd::time()is appropriate for uses like the timestamp of a file. But for a more precise measurement of time, set astd::chrono::time_point<std::chrono::high_resolution_clock>object to the value returned bystd::chrono::high_resolution_clock::now(). - Timespan as CPU Clockticks
The C-Runtime keeps track of the amount of time elapsed since the library started running within your program. Query that value by callingstd::clock().
- Time as a String
- Basic Algorithms
- Search
The C-Runtime's basic implementation of linear search by_lfind()will returnNULLif the key does not already exist. Binary search bybsearch()expects the input to be both sorted and unique. - Quick Sort
The C-Runtime provides a built-inqsort()implementation of the Quick Sort algorithm.
- Search
- Executing a Shell Command
A "system call" is the execution of a shell command, as in callingsystem("echo MESSAGE").
- Math
- STL: Standard Template Library
- Collection Classes
- Sequence Collections
- Vector
- Construction
A STL "vector" is a dynamically-resizing array-of-values. There are many ways to construct a vector, such as initializing it from a literal value using brace-syntax:std::vector<int> veciVar = {0, 11, 22, 33};. - Size
STL implements a vector as having an allocation "capacity" (queried byveciVar.capacity()) that may be somewhat larger than that collection's current size (queried byveciVar.size()). - Equality
Operators==and!=compare two vector objects. If you want to compare a vector to some other kind of collection, then you need to use the more generalstd::equal()function. - Indexing
Both the C-array-operator (veciVar[3]) andveciVar.at(3)allow random access to a vector's items. They differ in how they handle the error of a non-existent item. Because either of them provides a reference to that item, indexing can be used for getting it and for setting it. A reference is also returned by the special names for the first and last itemsveciVar.front()andveciVar.back(). - Removing Items
Theerase()function removes an iterator-specified item from the vector, but doesn't do anything to that removed item. So if the item-type was a pointer, then you would still be responsible for any manual destruction of the actual object. To remove all items, useclear(). To remove the last item, usepop_back(). - Inserting Items
An inserted item does not need to have the exact same item-type as the vector, as long as it can be coerced into the vector's item-type. If there will be coercion, then insertion byemplace()will be faster thaninsert()becauseemplace()directly uses a single-parameter-cast-constructor instead of copy-constructing from a compiler-temporary that holds the coerced-value. To insert as the vector's last item, useemplace_back()orpush_back(). - Assignment
One vector can be assigned from another vector, using the=operator.
- Construction
- Vector of Bool
A special specializationstd::vector<bool>compresses each item to a single bit. For this special specialization, the indexing operator doesn't returnbool&. Instead, it returns a reference to an auxillary class that defines bothvecyVar[iIndex].flip()and a cast-operator for getting and setting itsboolvalue. - STL-Array
A "STL-array" (an instance of classstd::array<>) has a fixed size that is part of the templated type. - Deque
A "deque" (an instance of classstd::deque<>) has an array-of-values that can dynamically-resize in either direction. Unlike a vector, a deque's internal implementation does not store items in contiguous memory (so there is no "capacity"). Because a deque can grow in either direction, you can callpush_front()in addition topush_back(). - List
A "list" (an instance of classstd::list<>) is a doubly-linked-list. A list doesn't provide any random-access indexing. In order to access a particular item, you need to iterate to it. - Forward-List
A "forward-list" (an instance of classstd::forward_list<>) is a forward-link-only version of a STL list. Its iteration can only use++(not--).
- Vector
- Sorted Collections
- A Pair as one Item
A "pair" is an object whose type encapsulates two other types. A pair has a literal form, using braces:std::pair<char,int> ciVar = {'a',11};. Access each component asciVar.firstorciVar.second. Pair assignment (=operator) copies-by-value the two elements from source to destination. Usually, assignment's destination is another pair. However, pair-assignment could also usestd::tie()to decompose into two scalar variables. - Tuple
A "tuple" is like a pair, except that a tuple can have more than two elements:std::tuple<char,int,float> cifVar('a', 11, 1.1F);. Access each component asstd::get<0>(cifVar)orstd::get<1>(cifVar)orstd::get<2>(cifVar). - Map
- Construction
A "map" is a lookup-dictionary whose items are key/value pairs. Initializing a map from a literal value uses nested-brace-syntax:std::map<char,int> mapciVar= {{'a',0}, {'e',11}, {'i',22}, {'o',33}}; - Sort-Class
The ordering of items does not matter in a map-literal. What does matter is the "sort-class" template-parameter (the default isstd::less<>if omitted). The sort-class determines the actual item-ordering within STL's internal representation (by ordering their keys). When iterators use++and--, they follow that sort-class order (not the map-literal's apparent order). - Custom Sort-Class
You could define your own custom sort-class. - Size
Thesize()function reports how many items are in the map. Thecount('i')function reports how many items are in the map having that particular key (0 or 1 of them). - Equality
Map-equality depends on the order of items in their internal-representations (due to sort-class), not on the order of items in any literal-specficiation. - Indexing
A map can be indexed-by-key (a lookup operation). Use either the C-array-operator, theat()function, or thefind()function. These differ in how they deal with a non-existent key. - Removing Items
Theerase()function removes an item from a map. You can giveerase()either an iterator, or the key of the item that you want removed. - Inserting Items
The distinction between a map'sinsert()andemplacefunctions is the same as it was for vectors. With a map, you could also use C-array-indexing syntax, which will insert a new item if the map didn't already contain one with that key. - Assignment
Assignment using the=operator will remove all existing elements.
- Construction
- Multimap
A "multimap" (an instance of classstd::multimap<>) is the same as a map, except that multiple items are allowed to have the same key. - Set
A "set" (an instance of classstd::set<>) is the same as a map, except that each item contains only the key (there is no value). - Multiset
A "multiset" (an instance of classset::multiset<>) is the same as a set, except that the same item can occur multiple times. - Hash-Table
The standard sorted collections each have an alternative implementation that is based on a hash-table. For example, instead of usingstd::map<char,int>, you might choose to usestd::unordered_map<char,int,std::hash<char>>.
- A Pair as one Item
- Sequence Collections
- Iterators
- Basic Iterators
Various kinds of "iterators" collectively act as a common interface (designed to resemble the API of a C pointer) between multiple kinds of collection classes and multiple algorithms:void OutputVector(std::vector<int>& x) {std::vector<int>::iterator piIter;for (piIter = x.begin(); piIter != x.end(); ++piIter) {int iVar = *piIter;std::cout << iVar;}} - Ranges
Often, a client uses parameters to specify a range of items to a STL algorithm. The convention is that the range's beginning is always inclusive, and its ending is always exclusive. To specify a range that involves all items, program asfind(veciVar.begin(), veciVar.end(), 11); - Insert-Iterators
Algorithmstd::copy()has already been written by STL to call operators=and++on both source and destination iterators (overwriting destination items with data copied from source items). As such, that algorithm assumes the destination collection must already have at least as many items as the source collection. Astd::back_insert_iterator<>"insert-iterator" is intermediary code which allows that same implementation ofstd::copy()to be used with an empty destination collection. That insert-iterator achieves this by re-defining the effect of operators=and++. Operator=now has the effect ofveciDesti.push_back(), and operator++now does nothing. - Reverse-Iterators
Similar to an insert-iterator, a "reverse-iterator" allows you to use STL's existingstd::copy()algorithm, but changes the effect that it has because of intermediary code that re-defines the iterator's operators. In this case, the result is a "reverse-copy effect". - Stream-Iterators
Like insert-iterators and reverse-iterators, using a "stream-iterator" changes the effect of STL's existing algorithms. In this case, the iterator's=operator gets re-defined to have the effect ofstd::cout << source << " ";. - Custom Iterators
It is possible to define your own custom iterator, by deriving fromstd::iterator<>.
- Basic Iterators
- Adapters
- Stack
A "STL adapter" exposes a theoretical data structure, with its storage being internally implemented by the usage of some existing collection class. By default,std::stack<int>uses a STL vector as its underlying collection class. This "stack" supports theoretical operationspush(123),pop(), and peeking (namedtop()). - Queue
By default,std::queue<int>uses a STL deque as its underlying collection class. This "queue" supports theoretical operationspush(123)(essentially just a re-naming ofpush_back()) andpop()(essentially just a re-naming ofpop_front()). - Binary-Heap
A "binary-heap" data structure maintains the theoretical "heap-property" in a "shaped-tree" whose maximum-item is always at the tree's root. Thisstd::priority_queue<int>binary-heap is useful if you need to be able to frequently identify and remove the largest item in a collection, without that collection having been linearly-sorted.
- Stack
- Callable-Objects
The purpose of a "callable-object" is to abstractly refer to one specific invoke-able subroutine. A callable-object exists as an instance ofstd::function<>.- A Function Name as a Value
The most simple form of a callable-object is the name of some existing function. If your software has already definedint DoAddition(int x, int y) {return x+y;}, then you might choose to define a callable-object asstd::function<int(int,int)> DoMath = DoAddition;. In this case, the callable-object (DoMath) is a variable that can be manipulated like any other C++ variable. But the special thing about a callable-object is that it can be "invoked", either by a function-call-operatorDoMath(11,22)or bystd::invoke(DoMath, 11, 22). - Member Function
A callable-object could also be assigned to a C++ member function:std::function<int(const CRType*,int,int)> DoMath= &CRType::DoAddition;
Now, invocation requires both parameters and athispointer (an address of some pre-existing target-object):DoMath(&oTargetObject, 11, 22). - Implicit Getter-Function
For every data member in a class, there is an implicit getter-function (even if the programmer didn't explicitly define that as a member function):std::function<int(const CRType*)> GetMember= &CRType::m_iMember; - Functor
A "functor" is any object defined to have a custom overload implementation of the function-call-operator (operator()). A functor object can be assigned to any callable-object whose signature matches. - Lambda
Just like aninthas a literal form (e.g.,123), a callable-object has a literal form called a "lambda". In this example, the literal is being assigned to a callable-object variable:std::function<int(int,int)> DoMath;DoMath = [](int x, int y) {return x + y;}; - Generic Lambda
A lambda can be written in a generic way, by usingautofor its parameter type. - Binding a new Function
One callable-object can be transformed into another (unnamed) callable-object by "binding" it usingstd::bind().
- A Function Name as a Value
- Algorithms
- Usage with a C-Array
A C-pointer implements operations (e.g.,++) that some STL algorithms expect from their iterators. Thus, some algorithms (includingstd::copy()) allow you to use a C-array as if it were a STL collection. - Querying
- Counting
A sorted collection has a built-inmapciVar.count('i')member function that is most efficient. But for a sequence collection, you need to use thecount()algorithm. - Searching
The algorithmstd::find_if(x.begin(), x.end(), callableObject)returns an iterator to the first item that it finds satisfying the callable-object (which must return abool). - Accumulating
Thestd::accumulate()algorithm iterates over items, accumulating them into a summation (or into some other kind of combination, if you provide a custom callable-object for doing each accumulation step).
- Counting
- Applying Item-by-Item
- Processing Item-by-Item
If you have a function likevoid DoubleEach(int& x) { x *= 2; }, then you can repeatedly apply that same callable-object, once per collection item. The algorithm to do so isstd::for_each(v.begin(), v.end(), DoubleEach). - Ignoring Prior Values
Unlike theDoubleEach()example, this function ignores existing item-values:int Compute99() { return 99; }. The algorithm to use it isstd::generate(v.begin(), v.end(), Compute99). - Item-by-Item Combination of Two Collections
Thestd::transform()algorithm combines two collections, item-by-item.
- Processing Item-by-Item
- Modifying
- Copying
If you have an appropriate callable-object, then copying can be conditional, with item-by-item testing of that condition:std::copy_if(src.begin(),src.end(),desti.begin(),IsOdd). - Removing
Thestd::remove()algorithm doesn't actually remove any items. Instead, it shifts the items-to-be-removed to the end of the collection. You need to call the collection class' item-removal function in order to complete the removal process. - Reordering
Thestd::sort()algorithm uses a predicate callable-object for all of its internal comparisons between two items. That predicate defaults tostd::less<>().
- Copying
- Usage with a C-Array
- Collection Classes
- Strings
- Unicode
An 8-bit "Ascii character" has typechar(its literal values arechar cVar = 'h';and"hello", its Standard Library functions are named likestrlen(), and its Win32 functions are named likeSetWindowTextA()). A "wide-Unicode character" has typewchar_t(its literal values arewchar_t cwVar = L'h';andL"hello", its Standard Library functions are named likedwcslen(), and its Win32 functions are named likeSetWindowTextW()). Windows programmers use preprocessor macros inTCHAR cxVar = _TEXT('h');to alias eitherchar cxVar = 'h';orwchar_t cxVar = L'h';(these macros are controlled by Windows' build system). That same switching mechanism also controls the expansion of macros_tcslen()andSetWindowText(). - Avoiding Buffer-Overrun
Some of the original C-Runtime functions were succeptible to a buffer-overrun-hack. For example,strnlen(NULL, 16)would cause a runtime-error. A safer alternative is available in Win32;strnlen_s(NULL, 16)simply returns0without trying to overrun the buffer. - Character Categories
There are functions for classifying a character as belonging to a category. The examplesisdigit('0'),isspace(' '), andispunct('!')all return true (in the form of a non-zerointvalue). - C-String Manipulation
A traditional C "string" is simply an array ofchar, where the end of the string data is terminated by a'\0'character. That terminating character is relied upon (but not counted) whenstrlen("abcde")measures that string's length to be 5. The lexicographical ordering of two C-strings is compared bystrcmp(). To copy C-string data to some otherchar-array buffer, usestrcpy()(orstrcat(), which will concatenate by starting at the end of existing data). - String Class
- Construction
An object-oriented approach to storing string data is C++'sstd::stringobject, which can dynaically-grow because it implements many of the same functions as an STL vector. Instead of using'\0'to terminate string data, you can query itsstrVar.size()function. Astd::stringobject can be treated as a value (e.g., passing it into some function as a parameter value), because copy-construction has been provided. Initializing a string asstd::string strVar("abc");is equivalent tostd::string strVar = {'a', 'b', 'c'};. - Equality
The==operator exists for comparing the data inside twostd::stringobjects. - Indexing
Like any STL collection, you could iterate through string data usingstd::string::iterator. Astd::stringobject uses contiguous memory for storing its characters. Application code is allowed to directly access the un-terminated character data (either viachar* pcVar = &strVar[0];orchar* pcVar = strVar.data();) as long as it stays within the string's allocation area, and finishes its work before the nextstd::stringoperation. More conveniently,strVar.c_str()is likestrVar.data()except thatc_str()temporarily adds a'\0'at the end of the data-characters (making the buffer temporarily compatible with C-Runtime functions). - Inserting Characters
Strings have anappend()function (or the+operator) for appending a whole string at a time. - Algorithms
A family offind()query algorithms returnbasic_string::npos(which is -1) to indicate "pattern is not found".
- Construction
- Casting Numeric Values
- Number to String
Formatted-printed bysprintf(pcBuffer, "%d", 11);is an easy way to cast from a number into a string. The more modernstd::format("1+2={} and 4+5={}", 3, 9)outputs its formatted-string as astd::stringobject. - String to Number
The inverse of formatted-printing can cast from a C-string into a numeric variable:sscanf("11", "&d", &iVar);.
- Number to String
- Aliased Strings
The newerstd::string_viewclass is likestd::string, except that its copy-construction does aliasing instead of copying character data. - Regular Expressions
Thestd::regex_match()function compares an input string against the regular expression pattern stored in astd::regexobject. The result of that matching is output into astd::cmatchobject (which can be converted into astd::stringbystr()). - Locale
The behavior of some string functions will depend on the computer system's "locale" setting. The Win32 implementation of some functions (e.g.,atoi()) have a locale-sensitive alternative (atoi_l()).
- Unicode
- IOStreams
- Stringstream
A "stream" uses operator<<to stream from general-purpose-data into a character sequence. A stream uses operator>>to stream the other direction. One possible place where the character sequence could go is into astd::stringstreamobject, which captures the character sequence as a C++ variable. That variable can then be accessed as a read-only string. Alternatively, a character sequence can be output to the Console by streaming tostd::cout. Alternatively, a character sequence can be streamed out to a file in the filesystem. - Streaming Custom Types
To enablestd::cout << oVar;whereoVarhas a custom type, you would need to implement an overload of the stream-operatoroperator<<().
- Stringstream
- Filesystem Access
- Moving and Deleting
An existing directory or file can be moved by usingrename()to change its name. An existing directory or file can be deleted byremove(). - Directories
Concatenating drive, directory, filename, and extension strings into one long path string used to be done by_makepath(), but now thestd::filesystem::pathcan do so more elegantly (using its/operator). Some of the most common OS shell commands have C++ versions, such as_chdir(),_mkdir(), and_rmdir(). - Binary-Files
A binary-standard-file is opened byFILE* poFile = fopen("pathandfile", "w+b");and closed byfclose(pofile);. The file has a "seek-pointer", which is the position (measured from the file's beginning) where the nextfwrite()orfread()operation will occur. That seek-pointer could be queried byftell()or moved byfseek(). - Formatted I/O
A standard-file can also use the formatted-operationsfprintf()andfscanf(). - Newline-Converted-Files
If you know that a file's data is to be interpreted as characters, then you could choose to have special operating-system-conversion of every newline character. To use that kind of "newline-converted-file", open it with"w+"instead of"w+b". - Size of a File
There are two ways of measuring a file's size. Either call_filelength(), or access thest_sizedata member of an object returned by_fstat(). - Redirecting stdout
The_dup()function is useful for redirectingstdoutto a file written on the disk. - Pipes
A "pipe" is like a name-less file, used for interprocess communication. - Console I/O
The_kbhit()function pauses until console-user presses a key. Then,_inp()reads a byte from the console. - Streamed I/O
An IOStreams stream can target a file.
- Moving and Deleting
- Multithreading
- Thread Creation
To create a thread in modern C++, instantiatestd::thread, passing it a callable-object for the worker thread's entry point. To block yourself for an arbitrary amount of time, callstd::this_thread::sleep_for(). To block yourself until the worker thread has finished its work, calloThread.join(). - Critical Section
A "critical section" is a code fragment that should be treated as atomic because of how it uses shared variables or resources. Extra code (inserted before and after a critical section) should enforce the mutually exclusive execution property (a.k.a. "mutex" property) within this critical section without causing "deadlock" nor "starvation". - Atomic Values
If the only content of a critical section is the manipulation of one variable, then the easiest synchronization approach would be to usestd::atomic<>and its associated arithmetic functions. - Locks
The mutually exclusive execution property of a critical section is provided by a "lock" synchronization primitive (typestd::mutexwith functionslock()andunlock()). The lock maintains a record of which thread calledlock(), and only that "owner-thread" is allowed to callunlock(). - Events
An "event" is a signal communicated from one thread to another thread. - Return Value
To return a value from your worker thread, use astd::future<>return-value-getter object, whoseget()function will block your client thread if the worker thread hasn't yet calledset_value()on a correspondingstd::promise<>return-value-setter object. - Semaphores
- Resource Management
Multiple threads might share a limited number of resources. Now, your code fragment isn't a critical section (multiple threads can now act simultaneously), but semaphore-based synchronization is needed to manage the resource pool usingP()andV()functions that block a thread whenever all resources have been depleted. - Fragment Ordering
A semaphore can be used to order the execution of code fragments in different threads. In this case, the "resource" isn't a physical thing, it's permission to execute the subsequent code fragment. - Ring Buffer
In an architecture where one thread produces a stream of products while another thread consumes those products, putting a "ring buffer" between the threads will allow variation in the pace of production and consumption. - Readers and Writers
Semaphores provide a solution to the classic "Readers and Writers Problem", where threads are either trying to read or write a file (multiple reads can occur concurrently, but writes require exclusive access).
- Resource Management
- Monitors and Channels
A "monitor" is a class that combines/encapsulates shared variables, mutually-exclusive access to those variables, and any other synchronization needed.
- Thread Creation
- RNG: Random Number Generator
The RNG from the Standard Libraries (std::random_device) is of better quality than the obsolete implementation in the original C-Runtime.
- C-Runtime
- Obsolete Features
- Trigraph Characters
The preprocessor used to support weak keyboards by allowing "trigraphs" (e.g., typing??!??!instead of||). - An Obsolete Smart Pointer
Typestd::auto_ptr<>is no longer used. - Variadics before ANSI
The pre-ANSIvarargs.hhas been replaced bystdarg.h. - Obsolete Function Binding
Some callable-object classes (std::unary_function<>) and functions (std::bind1st()) are now obsolete. - Boost Feature Graduation
Some Boost features are now obsolete because they have been moved into the official language.
- Trigraph Characters