Cplusplus
Cplusplus
#c++
Table of Contents
About 1
Remarks 2
Versions 2
Examples 2
Hello World 2
Analysis 2
Comments 4
Single-Line Comments 4
C-Style/Block Comments 4
Importance of Comments 5
Function 6
Function Declaration 6
Function Call 7
Function Definition 7
Function Overloading 8
Default Parameters 8
Preprocessor 11
Chapter 2: Alignment 13
Introduction 13
Remarks 13
Examples 13
Controlling alignment 14
Introduction 17
Examples 17
Chapter 5: Arrays 19
Introduction 19
Examples 19
Array initialization 25
Syntax 27
Remarks 27
Examples 27
Multi-threaded Access 27
Chapter 7: Attributes 29
Syntax 29
Examples 29
[[noreturn]] 29
[[fallthrough]] 30
[[nodiscard]] 31
[[maybe_unused]] 32
Chapter 8: auto 34
Remarks 34
Examples 34
Remarks 38
Examples 38
Examples 40
int 40
bool 40
char 40
char16_t 40
char32_t 41
float 41
double 41
long 41
short 42
void 42
wchar_t 42
Introduction 44
Remarks 44
Examples 45
Remarks 46
Examples 46
Setting a bit 46
Clearing a bit 46
C-style bit-manipulation 46
Using std::bitset 47
Toggling a bit 47
C-style bit-manipulation 47
Using std::bitset 47
Checking a bit 47
C-style bit-manipulation 47
Using std::bitset 48
C-style bit-manipulation 48
Using std::bitset 48
C-style bit-manipulation 48
Using std::bitset 48
C-style bit-manipulation 48
Remarks 52
Examples 52
| - bitwise OR 53
Remarks 58
Examples 58
Introduction 59
Basic rules 59
Incremental builds 60
Documentation 61
Ninja 62
Introduction 62
Introduction 62
Autotools (GNU) 63
Introduction 63
Introduction 64
Examples 64
Reserved Keywords 64
goto or switch 64
Introduction 65
Examples 65
Introduction 68
Remarks 68
Examples 68
Clean code 71
Conclusion 73
Static analysis 73
Compiler warnings 74
External tools 74
Other tools 75
Conclusion 75
Conclusion 76
Introduction 77
Examples 77
Call by value 77
Remarks 79
Examples 79
String streams 79
Copying streams 81
Arrays 82
Printing collections with iostream 82
Basic printing 82
Arrays 83
Parsing files 83
Transformation 84
Remarks 86
Atomic Operations 86
Sequential Consistency 87
Relaxed Ordering 87
Release-Acquire Ordering 87
Release-Consume Ordering 88
Fences 88
Examples 88
Fence example 90
Introduction 92
Remarks 92
Examples 92
Function Pointers 92
Syntax 94
Remarks 94
Examples 94
Class basics 94
Access specifiers 95
Inheritance 96
Virtual Inheritance 98
Multiple Inheritance 99
Background 102
Friendship 104
Examples 122
Examples 127
Variables 127
Functions 127
Introduction 130
Remarks 130
Examples 130
Introduction 153
Remarks 153
Examples 153
Syntax 157
Remarks 157
Examples 157
Syntax 167
Remarks 167
Examples 167
Examples 171
Introduction 173
Remarks 173
Examples 173
Examples 179
Syntax 184
Parameters 184
Remarks 184
Examples 184
Introduction 188
Examples 188
Examples 195
Introduction 197
Examples 197
Introduction 199
Remarks 199
Examples 199
Examples 209
Examples 210
Examples 214
std::uncaught_exceptions 220
Introduction 224
Syntax 224
Remarks 224
Examples 225
void* to T* 230
Examples 232
File vec.hh : wrapper for std::vector, used to show log when a construction is called. 234
File expr.hh : implementation of expression templates for element-wise operations (vector 235
Introduction 246
Examples 246
Examples 258
Remarks 260
Examples 260
case 260
switch 260
catch 261
default 261
if 262
else 262
goto 262
return 263
throw 263
try 264
Conditional Structures: if, if..else 264
Remarks 270
Examples 270
Introduction 273
Examples 273
Introduction 276
Remarks 276
Examples 276
Remarks 281
Examples 281
Introduction 282
Examples 282
Remarks 287
Examples 287
Examples 290
Introduction 298
Syntax 298
Remarks 298
FAQs 298
See Also 299
Examples 299
Introduction 301
Examples 301
Remarks 302
Examples 302
Examples 304
break 304
continue 304
do 304
for 304
while 305
Examples 306
Overview 307
Introduction 315
Syntax 315
Remarks 315
Examples 317
asm 317
explicit 317
noexcept 318
typename 319
sizeof 320
Syntax 326
Parameters 326
Remarks 326
Examples 327
Remarks 343
Examples 343
Arrays 346
Introduction 348
Syntax 348
Remarks 348
Examples 348
Introduction 350
Examples 350
true 350
false 350
nullptr 350
this 351
Introduction 354
Syntax 354
Remarks 354
Examples 354
Syntax 365
Remarks 365
Examples 365
Stack 365
Introduction 370
Remarks 370
Examples 370
If-then-else 379
Introduction 380
Examples 380
Examples 381
Examples 389
Remarks 391
Examples 399
std::mutex 401
std::lock 402
Introduction 403
Syntax 403
Remarks 403
Examples 404
What are namespaces? 404
Syntax 413
Remarks 413
Examples 413
Encapsulation 414
Examples 421
Introduction 424
Remarks 424
Examples 424
Remarks 440
Examples 440
Introduction 444
Examples 444
Examples 446
Example 449
When to use? 450
Remarks 452
Examples 452
Examples 461
Remarks 462
Examples 462
Remarks 464
Examples 464
Introduction 466
Syntax 466
Remarks 466
Examples 466
Syntax 472
Examples 472
Examples 476
Introduction 480
Remarks 480
Examples 480
Macros 483
X-macros 489
Examples 493
Profiling CPU Usage with gcc and Google Perf Tools 495
Remarks 498
Examples 498
Locking 498
Finally/ScopeExit 499
Remarks 503
Examples 503
Examples 506
Using tail recursion and Fibonnaci-style recursion to solve the Fibonnaci sequence 506
Examples 508
std::recursive_mutex 508
Introduction 509
Examples 509
Examples 513
Defining a reference 513
Introduction 515
Syntax 515
Parameters 515
Examples 516
Quantifiers 518
Anchors 520
Introduction 521
Examples 521
Remarks 524
Examples 524
1. Base example without covariant returns, shows why they're desirable 524
2. Covariant result version of the base example, static type checking. 525
Introduction 528
Examples 528
Examples 536
dynamic_cast 536
Examples 538
Introduction 540
Examples 540
Examples 542
enable_if 542
void_t 544
is_detected 548
Chapter 100: Side by Side Comparisons of classic C++ examples solved via C++ vs C++11 vs C
552
Examples 552
Remarks 554
Examples 554
Subclasses 555
Syntax 558
Remarks 558
Examples 558
Remarks 572
Examples 572
Destructor 584
Examples 587
std::for_each 587
std::next_permutation 587
std::accumulate 588
std::find 590
std::count 591
std::count_if 592
std::find_if 593
std::min_element 595
Syntax 598
Parameters 598
Remarks 598
Examples 598
static_assert 598
Remarks 600
Examples 600
Parameters 601
Remarks 601
Examples 601
Examples 606
Introduction 609
Remarks 609
Examples 609
Example 609
Methods 610
Examples 612
Introduction 619
Examples 619
Examples 622
std::setw 622
std::setprecision 622
std::setfill 623
std::setiosflags 623
Remarks 625
Examples 625
Multi-Map 632
Examples 634
Introduction 634
value_or 637
Examples 638
Introduction 640
Remarks 640
Examples 640
Introduction 647
Syntax 647
Remarks 648
Examples 648
Splitting 648
Concatenation 650
operator[](n) 651
at(n) 651
front() 651
back() 652
Tokenize 652
Remarks 664
Examples 664
Introduction 667
Remarks 667
Examples 667
Iterators: 675
Find max and min Element and Respective Index in a Vector 688
Introduction 691
Remarks 691
Examples 691
mutable 691
register 692
static 692
auto 693
extern 693
Introduction 695
Remarks 695
Examples 696
Introduction 706
Syntax 706
Remarks 706
Examples 708
Introduction 721
Remarks 721
Examples 722
C++11 722
Classes 723
Other Types 723
Templates 723
Concurrency 723
General 724
Concurrency 724
C++14 724
C++17 725
C++03 726
C++98 726
C++20 727
Examples 728
Remarks 734
Examples 734
Using the this Pointer to Differentiate Between Member Data and Parameters 737
Introduction 743
Examples 743
std::shared_lock 743
Syntax 746
Parameters 746
Remarks 746
Examples 746
Remarks 758
Examples 758
Remarks 760
Examples 760
Introduction 764
Examples 764
Introduction 777
Remarks 777
Examples 777
Examples 779
class 779
struct 780
enum 780
union 781
Chapter 134: Type Traits 783
Remarks 783
Examples 783
Constants 783
Functions 783
Types 784
Introduction 788
Syntax 788
Examples 788
Introduction 791
Remarks 791
Examples 792
Deleting a derived object via a pointer to a base class that doesn't have a virtual destru 798
Remarks 806
Examples 806
Introduction 808
Examples 808
Catch 808
Examples 810
Remarks 812
Examples 812
Examples 818
Introduction 822
Syntax 822
Remarks 822
Examples 822
Introduction 824
Remarks 824
Examples 824
Declaration and Usage 824
Examples 826
Definitions 828
Examples 830
prvalue 830
xvalue 831
lvalue 831
glvalue 831
rvalue 832
Examples 834
const 834
decltype 834
signed 835
unsigned 835
volatile 836
Syntax 837
Remarks 837
Examples 837
Credits 844
About
You can share this PDF with anyone you feel could benefit from it, downloaded the latest version
from: cplusplus
It is an unofficial and free C++ ebook created for educational purposes. All the content is extracted
from Stack Overflow Documentation, which is written by many hardworking individuals at Stack
Overflow. It is neither affiliated with Stack Overflow nor official C++.
The content is released under Creative Commons BY-SA, and the list of contributors to each
chapter are provided in the credits section at the end of this book. Images may be copyright of
their respective owners unless otherwise specified. All trademarks and registered trademarks are
the property of their respective company owners.
Use the content presented in this book at your own risk; it is not guaranteed to be correct nor
accurate, please send your feedback and corrections to [email protected]
https://riptutorial.com/ 1
Chapter 1: Getting started with C++
Remarks
The 'Hello World' program is a common example that can be simply used to check compiler and
library presence. It uses the C++ standard library, with std::cout from <iostream>, and has only one
file to compile, minimizing the chance of possible user error during compilation.
The process for compiling a C++ program inherently differs between compilers and operating
systems. The topic Compiling and Building contains the details about how to compile C++ code on
different platforms for a variety of compilers.
Versions
Examples
Hello World
#include <iostream>
int main()
{
std::cout << "Hello World!" << std::endl;
}
https://riptutorial.com/ 2
Analysis
Let's examine each part of this code in detail:
• #include <iostream> is a preprocessor directive that includes the content of the standard
C++ header file iostream.
iostream is a standard library header file that contains definitions of the standard input and
output streams. These definitions are included in the std namespace, explained below.
The standard input/output (I/O) streams provide ways for programs to get input from and
output to an external system -- usually the terminal.
• int main() { ... }defines a new function named main. By convention, the main function is
called upon execution of the program. There must be only one main function in a C++
program, and it must always return a number of the int type.
Here, the int is what is called the function's return type. The value returned by the main
function is an exit code.
If no return statement is present, the main function (and thus, the program itself) returns 0 by
default. In this example, we don't need to explicitly write return 0;.
All other functions, except those that return the void type, must explicitly return a value
according to their return type, or else must not return at all.
• std::cout << "Hello World!" << std::endl; prints "Hello World!" to the standard output
stream:
○ std is a namespace, and :: is the scope resolution operator that allows look-ups for
objects by name within a namespace.
There are many namespaces. Here, we use :: to show we want to use cout from the
std namespace. For more information refer to Scope Resolution Operator - Microsoft
Documentation.
○ std::coutis the standard output stream object, defined in iostream, and it prints to the
standard output (stdout).
○ <<is, in this context, the stream insertion operator, so called because it inserts an
object into the stream object.
The standard library defines the << operator to perform data insertion for certain data
types into output streams. stream << content inserts content into the stream and returns
the same, but updated stream. This allows stream insertions to be chained: std::cout
<< "Foo" << " Bar"; prints "FooBar" to the console.
https://riptutorial.com/ 3
○ "Hello World!" is a character string literal, or a "text literal." The stream insertion
operator for character string literals is defined in file iostream.
○ std::endl is a special I/O stream manipulator object, also defined in file iostream.
Inserting a manipulator into a stream changes the state of the stream.
The stream manipulator std::endl does two things: first it inserts the end-of-line
character and then it flushes the stream buffer to force the text to show up on the
console. This ensures that the data inserted into the stream actually appear on your
console. (Stream data is usually stored in a buffer and then "flushed" in batches unless
you force a flush immediately.)
○ The semicolon (;) notifies the compiler that a statement has ended. All C++ statements
and class definitions require an ending/terminating semicolon.
Comments
A comment is a way to put arbitrary text inside source code without having the C++ compiler
interpret it with any functional meaning. Comments are used to give insight into the design or
method of a program.
Single-Line Comments
The double forward-slash sequence // will mark all text until a newline as a comment:
int main()
{
// This is a single-line comment.
int a; // this also is a single-line comment
int i; // this is another single-line comment
}
C-Style/Block Comments
The sequence /* is used to declare the start of the comment block and the sequence */ is used to
declare the end of comment. All text between the start and end sequences is interpreted as a
comment, even if the text is otherwise valid C++ syntax. These are sometimes called "C-style"
comments, as this comment syntax is inherited from C++'s predecessor language, C:
https://riptutorial.com/ 4
int main()
{
/*
* This is a block comment.
*/
int a;
}
In any block comment, you can write anything you want. When the compiler encounters the
symbol */, it terminates the block comment:
int main()
{
/* A block comment with the symbol /*
Note that the compiler is not affected by the second /*
however, once the end-block-comment symbol is reached,
the comment ends.
*/
int a;
}
The above example is valid C++ (and C) code. However, having additional /* inside a block
comment might result in a warning on some compilers.
Block comments can also start and end within a single line. For example:
Importance of Comments
As with all programming languages, comments provide several benefits:
The need for comments can be reduced by writing clear, self-documenting code. A simple
example is the use of explanatory names for variables, functions, and types. Factoring out logically
related tasks into discrete functions goes hand-in-hand with this.
https://riptutorial.com/ 5
During development, comments can also be used to quickly disable portions of code without
deleting it. This is often useful for testing or debugging purposes, but is not good style for anything
other than temporary edits. This is often referred to as “commenting out”.
Similarly, keeping old versions of a piece of code in a comment for reference purposes is frowned
upon, as it clutters files while offering little value compared to exploring the code's history via a
versioning system.
Function
Functions can accept arguments or values and return a single value (or not). To use a function, a
function call is used on argument values and the use of the function call itself is replaced with its
return value.
Every function has a type signature -- the types of its arguments and the type of its return type.
Functions are inspired by the concepts of the procedure and the mathematical function.
• Note: C++ functions are essentially procedures and do not follow the exact definition or rules
of mathematical functions.
Functions are often meant to perform a specific task. and can be called from other parts of a
program. A function must be declared and defined before it is called elsewhere in a program.
• Note: popular function definitions may be hidden in other included files (often for
convenience and reuse across many files). This is a common use of header files.
Function Declaration
A function declaration is declares the existence of a function with its name and type signature to
the compiler. The syntax is as the following:
int add2(int i); // The function is of the type (int) -> (int)
In the example above, the int add2(int i) function declares the following to the compiler:
The first argument will be referred to in the function's contents by the name i.
○
The argument name is optional; the declaration for the function could also be the following:
https://riptutorial.com/ 6
Per the one-definition rule, a function with a certain type signature can only be declared or
defined once in an entire C++ code base visible to the C++ compiler. In other words, functions with
a specific type signature cannot be re-defined -- they must only be defined once. Thus, the
following is not valid C++:
int add2(int i); // The compiler will note that add2 is a function (int) -> int
int add2(int j); // As add2 already has a definition of (int) -> int, the compiler
// will regard this as an error.
If a function returns nothing, its return type is written as void. If it takes no parameters, the
parameter list should be empty.
void do_something(); // The function takes no parameters, and does not return anything.
// Note that it can still affect variables it has access to.
Function Call
A function can be called after it has been declared. For example, the following program calls add2
with the value of 2 within the function of main:
#include <iostream>
int main()
{
std::cout << add2(2) << "\n"; // add2(2) will be evaluated at this point,
// and the result is printed.
return 0;
}
Function Definition
A function definition* is similar to a declaration, except it also contains the code that is executed
when the function is called within its body.
int add2(int i) // Data that is passed into (int i) will be referred to by the name i
{ // while in the function's curly brackets or "scope."
https://riptutorial.com/ 7
// add2.
}
Function Overloading
You can create multiple functions with the same name but different parameters.
int add2(int i, int j) // However, when add2() is called with two parameters, the
{ // code from the initial declaration will be overloaded,
int k = i + j + 2 ; // and the code in this declaration will be evaluated
return k; // instead.
}
Both functions are called by the same name add2, but the actual function that is called depends
directly on the amount and type of the parameters in the call. In most cases, the C++ compiler can
compute which function to call. In some cases, the type must be explicitly stated.
Default Parameters
Default values for function parameters can only be specified in function declarations.
In this example, multiply() can be called with one or two parameters. If only one parameter is
given, b will have default value of 7. Default arguments must be placed in the latter arguments of
the function. For example:
Certain special character sequences that will be reduced to function calls by the compiler, such as
!, +, -, *, %, and << and many more. These special characters are normally associated with non-
https://riptutorial.com/ 8
programming usage or are used for aesthetics (e.g. the + character is commonly recognized as the
addition symbol both within C++ programming as well as in elementary math).
C++ handles these character sequences with a special syntax; but, in essence, each occurrence
of an operator is reduced to a function call. For example, the following C++ expression:
3+3
operator+(3, 3)
While in C++'s immediate predecessor, C, operator function names cannot be assigned different
meanings by providing additional definitions with different type signatures, in C++, this is valid.
"Hiding" additional function definitions under one unique function name is referred to as operator
overloading in C++, and is a relatively common, but not universal, convention in C++.
In C++, code must be declared or defined before usage. For example, the following produces a
compile time error:
int main()
{
foo(2); // error: foo is called, but has not yet been declared
}
There are two ways to resolve this: putting either the definition or declaration of foo() before its
usage in main(). Here is one example:
int main()
{
foo(2); // OK: foo is completely defined beforehand, so it can be called here.
}
https://riptutorial.com/ 9
}
The prototype must specify the return type (void), the name of the function (foo), and the argument
list variable types (int), but the names of the arguments are NOT required.
One common way to integrate this into the organization of source files is to make a header file
containing all of the prototype declarations:
// foo.h
void foo(int); // prototype declaration
and then, once compiled, link the corresponding object file foo.o into the compiled object file
where it is used in the linking phase, main.o:
An “unresolved external symbol” error occurs when the function prototype and call exist, but the
function body is not defined. These can be trickier to resolve as the compiler won't report the error
until the final linking stage, and it doesn't know which line to jump to in the code to show the error.
A compiler is a program that translates code from a programming language into another form
which is (more) directly executable for a computer. Using a compiler to translate code is called
compilation.
C++ inherits the form of its compilation process from its "parent" language, C. Below is a list
showing the four major steps of compilation in C++:
1. The C++ preprocessor copies the contents of any included header files into the source code
file, generates macro code, and replaces symbolic constants defined using #define with their
values.
2. The expanded source code file produced by the C++ preprocessor is compiled into assembly
https://riptutorial.com/ 10
language appropriate for the platform.
3. The assembler code generated by the compiler is assembled into appropriate object code for
the platform.
4. The object code file generated by the assembler is linked together with the object code files
for any library functions used to produce an executable file.
• Note: some compiled code is linked together, but not to create a final program. Usually, this
"linked" code can also be packaged into a format that can be used by other programs. This
"bundle of packaged, usable code" is what C++ programmers refer to as a library.
Many C++ compilers may also merge or un-merge certain parts of the compilation process for
ease or for additional analysis. Many C++ programmers will use different tools, but all of the tools
will generally follow this generalized process when they are involved in the production of a
program.
The link below extends this discussion and provides a nice graphic to help. [1]:
http://faculty.cs.niu.edu/~mcmahon/CS241/Notes/compile.html
Preprocessor
It edits the source code, cutting some bits out, changing others, and adding other things.
In source files, we can include preprocessor directives. These directives tells the preprocessor to
perform specific actions. A directive starts with a # on a new line. Example:
#define ZERO 0
#include <something>
directive. What it does is takes all of something and inserts it in your file where the directive was.
The hello world program starts with the line
#include <iostream>
This line adds the functions and objects that let you use the standard input and output.
The C language, which also uses the preprocessor, does not have as many header files as the
C++ language, but in C++ you can use all the C header files.
https://riptutorial.com/ 11
directive. This tells the preprocessor that as it goes along the file, it should replace every
occurrence of something with something_else. It can also make things similar to functions, but that
probably counts as advanced C++.
The something_else is not needed, but if you define something as nothing, then outside preprocessor
directives, all occurrences of something will vanish.
This actually is useful, because of the #if,#else and #ifdef directives. The format for these would
be the following:
#if something==true
//code
#else
//more code
#endif
#ifdef thing_that_you_want_to_know_if_is_defined
//code
#endif
These directives insert the code that is in the true bit, and deletes the false bits. this can be used
to have bits of code that are only included on certain operating systems, without having to rewrite
the whole code.
https://riptutorial.com/ 12
Chapter 2: Alignment
Introduction
All types in C++ have an alignment. This is a restriction on the memory address that objects of that
type can be created within. A memory address is valid for an object's creation if dividing that
address by the object's alignment is a whole number.
Remarks
The standard guarantees the following:
• The alignment requirement of a type is a divisor of its size. For example, a class with size 16
bytes could have an alignment of 1, 2, 4, 8, or 16, but not 32. (If a class's members only total
14 bytes in size, but the class needs to have an alignment requirement of 8, the compiler will
insert 2 padding bytes to make the class's size equal to 16.)
• The signed and unsigned versions of an integer type have the same alignment requirement.
• A pointer to void has the same alignment requirement as a pointer to char.
• The cv-qualified and cv-unqualified versions of a type have the same alignment requirement.
Note that while alignment exists in C++03, it was not until C++11 that it became possible to query
alignment (using alignof) and control alignment (using alignas).
Examples
Querying the alignment of a type
c++11
The alignment requirement of a type can be queried using the alignof keyword as a unary
operator. The result is a constant expression of type std::size_t, i.e., it can be evaluated at
compile time.
#include <iostream>
int main() {
std::cout << "The alignment requirement of int is: " << alignof(int) << '\n';
}
Possible output
If applied to an array, it yields the alignment requirement of the element type. If applied to a
https://riptutorial.com/ 13
reference type, it yields the alignment requirement of the referenced type. (References themselves
have no alignment, since they are not objects.)
Controlling alignment
C++11
The alignas keyword can be used to force a variable, class data member, declaration or definition
of a class, or declaration or definition of an enum, to have a particular alignment, if supported. It
comes in two forms:
• alignas(x), where x is a constant expression, gives the entity the alignment x, if supported.
• alignas(T), where T is a type, gives the entity an alignment equal to the alignment
requirement of T, that is, alignof(T), if supported.
If multiple alignas specifiers are applied to the same entity, the strictest one applies.
In this example, the buffer buf is guaranteed to be appropriately aligned to hold an int object, even
though its element type is unsigned char, which may have a weaker alignment requirement.
alignas cannot be used to give a type a smaller alignment than the type would have without this
declaration:
alignas, when given an integer constant expression, must be given a valid alignment. Valid
alignments are always powers of two, and must be greater than zero. Compilers are required to
support all valid alignments up to the alignment of the type std::max_align_t. They may support
larger alignments than this, but support for allocating memory for such objects is limited. The
upper limit on alignments is implementation dependent.
C++17 features direct support in operator new for allocating memory for over-aligned types.
https://riptutorial.com/ 14
Chapter 3: Argument Dependent Name
Lookup
Examples
What functions are found
Functions are found by first collecting a set of "associated classes" and "associated namespaces"
that include one ore more of the following, depending on the argument type T. First, let us show
the rules for classes, enumeration and class template specialization names.
All functions and templates within all associated namespaces are found by argument dependent
lookup. In addition, namespace-scope friend functions declared in associated classes are found,
which are normally not visible. Using directives are ignored, however.
All of the following example calls are valid, without qualifying f by the namespace name in the call.
namespace A {
struct Z { };
namespace I { void g(Z); }
using namespace I;
https://riptutorial.com/ 15
// example calls
f(A::X());
f(A::X::Y());
f(std::make_shared<A::X>());
https://riptutorial.com/ 16
Chapter 4: Arithmitic Metaprogramming
Introduction
These are example of using C++ template metaprogramming in processing arithmitic operations in
compile time.
Examples
Calculating power in O(log n)
This example shows an efficient way of calculating power using template metaprogramming.
Example Usage:
C++14
https://riptutorial.com/ 17
intermediateValue;
};
int main()
{
std::cout << powerDouble<2,-3>::value;
}
https://riptutorial.com/ 18
Chapter 5: Arrays
Introduction
Arrays are elements of the same type placed in adjoining memory locations. The elements can be
individually referenced by a unique identifier with an added index.
This allows you to declare multiple variable values of a specific type and access them individually
without needing to declare a variable for each value.
Examples
Array size: type safe at compile time.
//----------------------------------- Machinery:
//----------------------------------- Usage:
#include <iostream>
using namespace std;
auto main()
-> int
{
int const a[] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 4};
Size const n = n_items( a );
int b[n] = {}; // An array of the same size as a.
(void) b;
cout << "Size = " << n << "\n";
}
The C idiom for array size, sizeof(a)/sizeof(a[0]), will accept a pointer as argument and will then
generally yield an incorrect result.
For C++11
std::extent<decltype(MyArray)>::value;
Example:
https://riptutorial.com/ 19
char MyArray[] = { 'X','o','c','e' };
const auto n = std::extent<decltype(MyArray)>::value;
std::cout << n << "\n"; // Prints 4
Up till C++17 (forthcoming as of this writing) C++ had no built-in core language or standard library
utility to obtain the size of an array, but this can be implemented by passing the array by reference
to a function template, as shown above. Fine but important point: the template size parameter is a
size_t, somewhat inconsistent with the signed Size function result type, in order to accommodate
the g++ compiler which sometimes insists on size_t for template matching.
With C++17 and later one may instead use std::size, which is specialized for arrays.
// Example of raw dynamic size array. It's generally better to use std::vector.
#include <algorithm> // std::sort
#include <iostream>
using namespace std;
auto main()
-> int
{
cout << "Sorting n integers provided by you.\n";
cout << "n? ";
int const n = int_from( cin );
int* a = new int[n]; // ← Allocation of array of n items.
sort( a, a + n );
for( int i = 0; i < n; ++i ) { cout << a[i] << ' '; }
cout << '\n';
delete[] a;
}
A program that declares an array T a[n]; where n is determined a run-time, can compile with
certain compilers that support C99 variadic length arrays (VLAs) as a language extension. But
VLAs are not supported by standard C++. This example shows how to manually allocate a
dynamic size array via a new[]-expression,
delete[] a;
https://riptutorial.com/ 20
The array allocated here has indeterminate values, but it can be zero-initialized by just adding an
empty parenthesis (), like this: new int[n](). More generally, for arbitrary item type, this performs a
value-initialization.
As part of a function down in a call hierarchy this code would not be exception safe, since an
exception before the delete[] expression (and after the new[]) would cause a memory leak. One
way to address that issue is to automate the cleanup via e.g. a std::unique_ptr smart pointer. But
a generally better way to address it is to just use a std::vector: that's what std::vector is there for.
int main()
{
cout << "Sorting integers provided by you.\n";
cout << "You can indicate EOF via F6 in Windows or Ctrl+D in Unix-land.\n";
vector<int> a; // ← Zero size by default.
while( cin )
{
cout << "One number, please, or indicate EOF: ";
int const x = int_from( cin );
if( !cin.fail() ) { a.push_back( x ); } // Expands as necessary.
}
std::vector is a standard library class template that provides the notion of a variable size array. It
takes care of all the memory management, and the buffer is contiguous so a pointer to the buffer
(e.g. &v[0] or v.data()) can be passed to API functions requiring a raw array. A vector can even be
expanded at run time, via e.g. the push_back member function that appends an item.
The complexity of the sequence of n push_back operations, including the copying or moving
involved in the vector expansions, is amortized O(n). “Amortized”: on average.
Internally this is usually achieved by the vector doubling its buffer size, its capacity, when a larger
buffer is needed. E.g. for a buffer starting out as size 1, and being repeatedly doubled as needed
for n=17 push_back calls, this involves 1 + 2 + 4 + 8 + 16 = 31 copy operations, which is less than
2×n = 34. And more generally the sum of this sequence can't exceed 2×n.
Compared to the dynamic size raw array example, this vector-based code does not require the
user to supply (and know) the number of items up front. Instead the vector is just expanded as
https://riptutorial.com/ 21
necessary, for each new item value specified by the user.
Output:
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
C++ doesn't support special syntax for indexing a multi-dimensional array. Instead such an array
is viewed as an array of arrays (possibly of arrays, and so on), and the ordinary single index
notation [i] is used for each level. In the example above m[y] refers to row y of m, where y is a
zero-based index. Then this row can be indexed in turn, e.g. m[y][x], which refers to the xth item –
or column – of row y.
I.e. the last index varies fastest, and in the declaration the range of this index, which here is the
number of columns per row, is the last and “innermost” size specified.
Since C++ doesn't provide built-in support for dynamic size arrays, other than dynamic allocation,
a dynamic size matrix is often implemented as a class. Then the raw array matrix indexing
notation m[y][x] has some cost, either by exposing the implementation (so that e.g. a view of a
transposed matrix becomes practically impossible) or by adding some overhead and slight
inconvenience when it's done by returning a proxy object from operator[]. And so the indexing
notation for such an abstraction can and will usually be different, both in look-and-feel and in the
order of indices, e.g. m(x,y) or m.at(x,y) or m.item(x,y).
https://riptutorial.com/ 22
A dynamic size matrix using std::vector for storage.
Unfortunately as of C++14 there's no dynamic size matrix class in the C++ standard library. Matrix
classes that support dynamic size are however available from a number of 3rd party libraries,
including the Boost Matrix library (a sub-library within the Boost library).
If you don't want a dependency on Boost or some other library, then one poor man's dynamic size
matrix in C++ is just like
vector<vector<int>> m( 3, vector<int>( 7 ) );
… where vector is std::vector. The matrix is here created by copying a row vector n times where n
is the number of rows, here 3. It has the advantage of providing the same m[y][x] indexing
notation as for a fixed size raw array matrix, but it's a bit inefficient because it involves a dynamic
allocation for each row, and it's a bit unsafe because it's possible to inadvertently resize a row.
A more safe and efficient approach is to use a single vector as storage for the matrix, and map the
client code's (x, y) to a corresponding index in that vector:
//--------------------------------------------- Machinery:
#include <algorithm> // std::copy
#include <assert.h> // assert
#include <initializer_list> // std::initializer_list
#include <vector> // std::vector
#include <stddef.h> // ptrdiff_t
namespace my {
using Size = ptrdiff_t;
using std::initializer_list;
using std::vector;
public:
auto n_rows() const -> Size { return items_.size()/n_cols_; }
auto n_cols() const -> Size { return n_cols_; }
https://riptutorial.com/ 23
Matrix(): n_cols_( 0 ) {}
//--------------------------------------------- Usage:
using my::Matrix;
auto some_matrix()
-> Matrix<int>
{
return
{
{ 1, 2, 3, 4, 5, 6, 7 },
{ 8, 9, 10, 11, 12, 13, 14 },
{ 15, 16, 17, 18, 19, 20, 21 }
};
}
#include <iostream>
#include <iomanip>
using namespace std;
auto main() -> int
{
Matrix<int> const m = some_matrix();
assert( m.n_cols() == 7 );
assert( m.n_rows() == 3 );
for( int y = 0, y_end = m.n_rows(); y < y_end; ++y )
{
for( int x = 0, x_end = m.n_cols(); x < x_end; ++x )
{
cout << setw( 4 ) << m.item( x, y ); // ← Note: not `m[y][x]`!
}
cout << '\n';
}
}
Output:
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
https://riptutorial.com/ 24
The above code is not industrial grade: it's designed to show the basic principles, and serve the
needs of students learning C++.
For example, one may define operator() overloads to simplify the indexing notation.
Array initialization
An array is just a block of sequential memory locations for a specific type of variable. Arrays are
allocated the same way as normal variables, but with square brackets appended to its name []
that contain the number of elements that fit into the array memory.
The following example of an array uses the typ int, the variable name arrayOfInts, and the
number of elements [5] that the array has space for:
int arrayOfInts[5];
An array can be declared and initialized at the same time like this
When initializing an array by listing all of its members, it is not necessary to include the number of
elements inside the square brackets. It will be automatically calculated by the compiler. In the
following example, it's 5:
It is also possible to initialize only the first elements while allocating more space. In this case,
defining the length in brackets is mandatory. The following will allocate an array of length 5 with
partial initialization, the compiler initializes all remaining elements with the standard value of the
element type, in this case zero.
Arrays of other basic data types may be initialized in the same way.
char arrayOfChars[5]; // declare the array and allocate the memory, don't initialize
char arrayOfChars[5] = { 'a', 'b', 'c', 'd', 'e' } ; //declare and initialize
It is also important to take note that when accessing array elements, the array's element index(or
position) starts from 0.
int array[5] = { 10/*Element no.0*/, 20/*Element no.1*/, 30, 40, 50/*Element no.4*/};
std::cout << array[4]; //outputs 50
std::cout << array[0]; //outputs 10
https://riptutorial.com/ 25
Read Arrays online: https://riptutorial.com/cplusplus/topic/3017/arrays
https://riptutorial.com/ 26
Chapter 6: Atomic Types
Syntax
• std::atomic<T>
• std::atomic_flag
Remarks
std::atomic allows atomic access to a TriviallyCopyable type, it is implementation-dependent if this
is done via atomic operations or by using locks. The only guaranteed lock-free atomic type is
std::atomic_flag.
Examples
Multi-threaded Access
An atomic type can be used to safely read and write to a memory location shared between two
threads.
#include <thread>
#include <iostream>
//function will add all values including and between 'a' and 'b' to 'result'
void add(int a, int b, int * result) {
for (int i = a; i <= b; i++) {
*result += i;
}
}
int main() {
//a primitive data type has no thread safety
int shared = 0;
https://riptutorial.com/ 27
//rejoin the thread at the end of execution for cleaning purposes
addingThread.join();
return 0;
}
The above example may cause a corrupted read and can lead to undefined behavior.
#include <atomic>
#include <thread>
#include <iostream>
//function will add all values including and between 'a' and 'b' to 'result'
void add(int a, int b, std::atomic<int> * result) {
for (int i = a; i <= b; i++) {
//atomically add 'i' to result
result->fetch_add(i);
}
}
int main() {
//atomic template used to store non-atomic objects
std::atomic<int> shared = 0;
return 0;
}
The above example is safe because all store() and load() operations of the atomic data type
protect the encapsulated int from simultaneous access.
https://riptutorial.com/ 28
Chapter 7: Attributes
Syntax
• [[details]]: Simple no-argument attribute
Examples
[[noreturn]]
C++11
C++11 introduced the [[noreturn]] attribute. It can be used for a function to indicate that the
function does not return to the caller by either executing a return statement, or by reaching the end
if it's body (it is important to note that this does not apply to void functions, since they do return to
the caller, they just do not return any value). Such a function may end by calling std::terminate or
std::exit, or by throwing an exception. It is also worth noting that such a function can return by
executing longjmp.
For instance, the function below will always either throw an exception or call std::terminate, so it is
a good candidate for [[noreturn]]:
This kind of functionality allows the compiler to end a function without a return statement if it
knows the code will never be executed. Here, because the call to ownAssertFailureHandler (defined
above) in the code below will never return, the compiler does not need to add code below that call:
https://riptutorial.com/ 29
}
It is undefined behavior if the function will actually return, so the following is not allowed:
Note that the [[noreturn]] is mostly used in void functions. However, this is not a requirement,
allowing the functions to be used in generic programming:
template<class InconsistencyHandler>
double fortyTwoDivideBy(int i) {
if (i == 0)
i = InconsistencyHandler::correct(i);
return 42. / i;
}
struct InconsistencyThrower {
static [[noreturn]] int correct(int i) { ownAssertFailureHandler("Unknown
inconsistency"s); }
}
struct InconsistencyChangeToOne {
static int correct(int i) { return 1; }
}
• std::abort
• std::exit
• std::quick_exit
• std::unexpected
• std::terminate
• std::rethrow_exception
• std::throw_with_nested
• std::nested_exception::rethrow_nested
[[fallthrough]]
C++17
Whenever a case is ended in a switch, the code of the next case will get executed. This last one
can be prevented by using the ´break` statement. As this so-called fallthrough behavior can
introduce bugs when not intended, several compilers and static analyzers give a warning on this.
https://riptutorial.com/ 30
From C++17 on, a standard attribute was introduced to indicate that the warning is not needed
when the code is meant to fall through. Compilers can safely give warnings when a case is ended
without break or [[fallthrough]] and has at least one statement.
switch(input) {
case 2011:
case 2014:
case 2017:
std::cout << "Using modern C++" << std::endl;
[[fallthrough]]; // > No warning
case 1998:
case 2003:
standard = input;
}
See the proposal for more detailed examples on how [[fallthrough]] can be used.
C++14
C++14 introduced a standard way of deprecating functions via attributes. [[deprecated]] can be
used to indicate that a function is deprecated. [[deprecated("reason")]] allows adding a specific
reason which can be shown by the compiler.
// Provides specific message which helps other programmers fixing there code
[[deprecated("Use the variant with unique_ptr instead, this function will be removed in the
next release")]]
void function(std::auto_ptr<A> a);
[[nodiscard]]
C++17
https://riptutorial.com/ 31
The [[nodiscard]] attribute can be used to indicate that the return value of a function shouldn't be
ignored when you do a function call. If the return value is ignored, the compiler should give a
warning on this. The attribute can be added to:
• A function definition
• A type
Adding the attribute to a type has the same behaviour as adding the attribute to every single
function which returns this type.
template<typename Function>
[[nodiscard]] Finally<std::decay_t<Function>> onExit(Function &&f);
See the proposal for more detailed examples on how [[nodiscard]] can be used.
Note: The implementation details of Finally/onExit are omitted in the example, see
Finally/ScopeExit.
[[maybe_unused]]
The [[maybe_unused]] attribute is created for indicating in code that certain logic might not be used.
This if often linked to preprocessor conditions where this might be used or might not be used. As
compilers can give warnings on unused variables, this is a way of suppressing them by indicating
intent.
A typical example of variables which are needed in debug builds while unneeded in production are
return values indicating success. In the debug builds, the condition should be asserted, though in
production these asserts have been removed.
A more complex example are different kind of helper functions which are in an unnamed
namespace. If these functions aren't used during compilation, a compiler might give a warning on
them. Ideally you would like to guard them with the same preprocessor tags as the caller, though
as this might become complex the [[maybe_unused]] attribute is a more maintainable alternative.
namespace {
[[maybe_unused]] std::string createWindowsConfigFilePath(const std::string &relativePath);
https://riptutorial.com/ 32
// TODO: Reuse this on BSD, MAC ...
[[maybe_unused]] std::string createLinuxConfigFilePath(const std::string &relativePath);
}
See the proposal for more detailed examples on how [[maybe_unused]] can be used.
https://riptutorial.com/ 33
Chapter 8: auto
Remarks
The keyword auto is a typename that represents an automatically-deduced type.
It was already a reserved keyword in C++98, inherited from C. In old versions of C++, it could be
used to explicitly state that a variable has automatic storage duration:
int main()
{
auto int i = 5; // removing auto has no effect
}
Examples
Basic auto sample
with lambdas:
https://riptutorial.com/ 34
auto myMap = std::map<int,float>();
myMap.emplace(1,3.14);
The reason for the copy is that the returned type is actually std::pair<const int,float>!
auto can also cause problems where expression templates come into play:
auto mult(int c) {
return c * std::valarray<int>{1};
}
auto v = mult(3);
std::cout << v[0]; // some value that could be, but almost certainly is not, 3.
The reason is that operator* on valarray gives you a proxy object that refers to the valarray as a
means of lazy evaluation. By using auto, you're creating a dangling reference. Instead of mult had
returned a std::valarray<int>, then the code would definitely print 3.
The auto keyword by itself represents a value type, similar to int or char. It can be modified with
the const keyword and the & symbol to represent a const type or a reference type, respectively.
These modifiers can be combined.
In this example, s is a value type (its type will be inferred as std::string), so each iteration of the
for loop copies a string from the vector into s.
If the body of the loop modifies s (such as by calling s.append(" and stuff")), only this copy will be
modified, not the original member of strings.
On the other hand, if s is declared with auto& it will be a reference type (inferred to be std::string&
), so on each iteration of the loop it will be assigned a reference to a string in the vector:
for(auto& s : strings) {
std::cout << s << std::endl;
}
In the body of this loop, modifications to s will directly affect the element of strings that it
references.
Finally, if s is declared const auto&, it will be a const reference type, meaning that on each iteration
https://riptutorial.com/ 35
of the loop it will be assigned a const reference to a string in the vector:
Within the body of this loop, s cannot be modified (i.e. no non-const methods can be called on it).
When using auto with range-based for loops, it is generally good practice to use const auto& if the
loop body will not modify the structure being looped over, since this avoids unnecessary copies.
which is equivalent to
int main() {}
C++14
auto print = [](const auto& arg) { std::cout << arg << std::endl; };
print(42);
print("hello world");
struct lambda {
template <typename T>
auto operator ()(const T& arg) const {
std::cout << arg << std::endl;
}
};
and then
lambda print;
https://riptutorial.com/ 36
print(42);
print("hello world");
Sometimes auto may behave not quite as was expected by a programmer. It type deduces the
expression, even when type deduction is not the right thing to do.
Here flag would be not bool, but std::vector<bool>::reference, since for bool specialization of
template vector the operator [] returns a proxy object with conversion operator operator bool
defined.
When flags.push_back(true) modifies the container, this pseudo-reference could end up dangling,
referring to an element that no longer exists.
std::vector<bool> getFlags();
The vector is discarded immediately, so flag is a pseudo-reference to an element that has been
discarded. The call to foo invokes undefined behavior.
In cases like this you can declare a variable with auto and initialize it by casting to the type you
want to be deduced:
but at that point, simply replacing auto with bool makes more sense.
Another case where proxy objects can cause problems is expression templates. In that case, the
templates are sometimes not designed to last beyond the current full-expression for efficiency
sake, and using the proxy object on the next causes undefined behavior.
https://riptutorial.com/ 37
Chapter 9: Basic input/output in c++
Remarks
The standard library <iostream> defines few streams for input and output:
|stream | description |
|-------|----------------------------------|
|cin | standard input stream |
|cout | standard output stream |
|cerr | standard error (output) stream |
|clog | standard logging (output) stream |
Out of four streams mentioned above cin is basically used for user input and other three are used
for outputting the data. In general or in most coding environments cin (console input or standard
input) is keyboard and cout (console output or standard output) is monitor.
cin here extracts the input entered by the user and feeds in variable value. The value is extracted
only after user presses ENTER key.
cout here takes the string to be displayed and inserts it to standard output or monitor
All four streams are located in standard namespace std so we need to print std::stream for stream
stream to use it.
There is also a manipulator std::endl in code. It can be used only with output streams. It inserts
end of line '\n' character in the stream and flushes it. It causes immediately producing output.
Examples
user input and standard output
#include <iostream>
int main()
{
https://riptutorial.com/ 38
int value;
std::cout << "Enter a value: " << std::endl;
std::cin >> value;
std::cout << "The square of entered value is: " << value * value << std::endl;
return 0;
}
https://riptutorial.com/ 39
Chapter 10: Basic Type Keywords
Examples
int
Denotes a signed integer type with "the natural size suggested by the architecture of the execution
environment", whose range includes at least -32767 to +32767, inclusive.
int x = 2;
int y = 3;
int z = x + y;
Can be combined with unsigned, short, long, and long long (q.v.) in order to yield other integer
types.
bool
bool is_even(int x) {
return x%2 == 0;
}
const bool b = is_even(47); // false
char
An integer type which is "large enough to store any member of the implementation’s basic
character set". It is implementation-defined whether char is signed (and has a range of at least -
127 to +127, inclusive) or unsigned (and has a range of at least 0 to 255, inclusive).
char16_t
C++11
An unsigned integer type with the same size and alignment as uint_least16_t, which is therefore
large enough to hold a UTF-16 code unit.
https://riptutorial.com/ 40
char32_t
C++11
An unsigned integer type with the same size and alignment as uint_least32_t, which is therefore
large enough to hold a UTF-32 code unit.
float
A floating point type. Has the narrowest range out of the three floating point types in C++.
double
A floating point type. Its range includes that of float. When combined with long, denotes the long
double floating point type, whose range includes that of double.
long
Denotes a signed integer type that is at least as long as int, and whose range includes at least -
2147483647 to +2147483647, inclusive (that is, -(2^31 - 1) to +(2^31 - 1)). This type can also be
written as long int.
The combination long double denotes a floating point type, which has the widest range out of the
three floating point types.
C++11
When the long specifier occurs twice, as in long long, it denotes a signed integer type that is at
least as long as long, and whose range includes at least -9223372036854775807 to
https://riptutorial.com/ 41
+9223372036854775807, inclusive (that is, -(2^63 - 1) to +(2^63 - 1)).
short
Denotes a signed integer type that is at least as long as char, and whose range includes at least -
32767 to +32767, inclusive. This type can also be written as short int.
void
An incomplete type; it is not possible for an object to have type void, nor are there arrays of void or
references to void. It is used as the return type of functions that do not return anything.
Moreover, a function may redundantly be declared with a single parameter of type void; this is
equivalent to declaring a function with no parameters (e.g. int main() and int main(void) declare
the same function). This syntax is allowed for compatibility with C (where function declarations
have a different meaning than in C++).
The type void* ("pointer to void") has the property that any object pointer can be converted to it
and back and result in the same pointer. This feature makes the type void* suitable for certain
kinds of (type-unsafe) type-erasing interfaces, for example for generic contexts in C-style APIs
(e.g. qsort, pthread_create).
Any expression may be converted to an expression of type void; this is called a discarded-value
expression:
This may be useful to signal explicitly that the value of an expression is not of interest and that the
expression is to be evaluated for its side effects only.
wchar_t
An integer type large enough to represent all characters of the largest supported extended
character set, also known as the wide-character set. (It is not portable to make the assumption
that wchar_t uses any particular encoding, such as UTF-16.)
It is normally used when you need to store characters over ASCII 255 , as it has a greater size
than the character type char.
https://riptutorial.com/ 42
const wchar_t message_chinese[] = L" \n";// Chinese for "hello, world\n"
const wchar_t message_hebrew[] = L"\םלוע םולשn"; //Hebrew for "hello, world\n"
const wchar_t message_russian[] = L"Привет мир\n"; //Russian for "hello, world\n"
const wchar_t message_tamil[] = L"ஹலோ உலகம்\n"; //Tamil for "hello, world\n"
https://riptutorial.com/ 43
Chapter 11: Bit fields
Introduction
Bit fields tightly pack C and C++ structures to reduce size. This appears painless: specify the
number of bits for members, and compiler does the work of co-mingling bits. The restriction is
inability to take the address of a bit field member, since it is stored co-mingled. sizeof() is also
disallowed.
The cost of bit fields is slower access, as memory must be retrieved and bitwise operations
applied to extract or modify member values. These operations also add to executable size.
Remarks
How expensive are the bitwise operations? Suppose a simple non-bit field structure:
struct foo {
unsigned x;
unsigned y;
}
static struct foo my_var;
my_var.y = 5;
If sizeof (unsigned) == 4, then x is stored at the start of the structure, and y is stored 4 bytes in.
Assembly code generated may resemble:
This is straightforward because x is not co-mingled with y. But imagine redefining the structure
with bit fields:
struct foo {
unsigned x : 4; /* Range 0-0x0f, or 0 through 15 */
unsigned y : 4;
}
Both x and y will be allocated 4 bits, sharing a single byte. The structure thus takes up 1 byte,
instead of 8. Consider the assembly to set y now, assuming it ends up in the upper nibble:
https://riptutorial.com/ 44
stb register1[0],register2 ; put the modified byte back into memory
This may be a good trade-off if we have thousands or millions of these structures, and it helps
keeps memory in cache or prevents swapping—or could bloat the executable to worsen these
problems and slow processing. As with all things, use good judgement.
Device driver use: Avoid bit fields as a clever implementation strategy for device drivers. Bit field
storage layouts are not necessarily consistent between compilers, making such implementations
non-portable. The read-modify-write to set values may not do what devices expect, causing
unexpected behaviors.
Examples
Declaration and Usage
struct FileAttributes
{
unsigned int ReadOnly: 1;
unsigned int Hidden: 1;
};
Here, each of these two fields will occupy 1 bit in memory. It is specified by : 1 expression after
the variable names. Base type of bit field could be any integral type (8-bit int to 64-bit int). Using
unsigned type is recommended, otherwise surprises may come.
If more bits are required, replace "1" with number of bits required. For example:
struct Date
{
unsigned int Year : 13; // 2^13 = 8192, enough for "year" representation for long time
unsigned int Month: 4; // 2^4 = 16, enough to represent 1-12 month values.
unsigned int Day: 5; // 32
};
The whole structure is using just 22 bits, and with normal compiler settings, sizeof this structure
would be 4 bytes.
Usage is pretty simple. Just declare the variable, and use it like ordinary structure.
Date d;
d.Year = 2016;
d.Month = 7;
d.Day = 22;
https://riptutorial.com/ 45
Chapter 12: Bit Manipulation
Remarks
In order to use std::bitset you will have to include <bitset> header.
#include <bitset>
std::bitset overloads all of the operator functions to allow the same usage as the c-style handling
of bitsets.
References
Examples
Setting a bit
Using std::bitset
set(x) or set(x,true) - sets bit at position x to 1.
std::bitset<5> num(std::string("01100"));
num.set(0); // num is now 01101
num.set(2); // num is still 01101
num.set(4,true); // num is now 11110
Clearing a bit
C-style bit-manipulation
A bit can be cleared using the bitwise AND operator (&).
https://riptutorial.com/ 46
// Bit x will be cleared
number &= ~(1LL << x);
Using std::bitset
reset(x) or set(x,false) - clears the bit at position x.
std::bitset<5> num(std::string("01100"));
num.reset(2); // num is now 01000
num.reset(0); // num is still 01000
num.set(3,false); // num is now 00000
Toggling a bit
C-style bit-manipulation
A bit can be toggled using the XOR operator (^).
Using std::bitset
std::bitset<4> num(std::string("0100"));
num.flip(2); // num is now 0000
num.flip(0); // num is now 0001
num.flip(); // num is now 1110 (flips all bits)
Checking a bit
C-style bit-manipulation
The value of the bit can be obtained by shifting the number to the right x times and then
performing bitwise AND (&) on it:
(number >> x) & 1LL; // 1 if the 'x'th bit of 'number' is set, 0 otherwise
The right-shift operation may be implemented as either an arithmetic (signed) shift or a logical
(unsigned) shift. If number in the expression number >> x has a signed type and a negative value, the
resulting value is implementation-defined.
If we need the value of that bit directly in-place, we could instead left shift the mask:
https://riptutorial.com/ 47
(number & (1LL << x)); // (1 << x) if the 'x'th bit of 'number' is set, 0 otherwise
Either can be used as a conditional, since all non-zero values are considered true.
Using std::bitset
std::bitset<4> num(std::string("0010"));
bool bit_val = num.test(1); // bit_val value is set to true;
C-style bit-manipulation
// Bit n will be set if x is 1 and cleared if x is 0.
number ^= (-x ^ number) & (1LL << n);
Using std::bitset
set(n,val) - sets bit n to the value val.
std::bitset<5> num(std::string("00100"));
num.set(0,true); // num is now 00101
num.set(2,false); // num is now 00001
C-style bit-manipulation
x = -1; // -1 == 1111 1111 ... 1111b
(See here for an explanation of why this works and is actually the best approach.)
Using std::bitset
std::bitset<10> x;
x.set(); // Sets all bits to '1'
https://riptutorial.com/ 48
C-style bit-manipulation
template <typename T>
T rightmostSetBitRemoved(T n)
{
// static_assert(std::is_integral<T>::value && !std::is_signed<T>::value, "type should be
unsigned"); // For c++11 and later
return n & (n - 1);
}
Explanation
The population count of a bitstring is often needed in cryptography and other applications and the
problem has been widely studied.
It goes through as many iterations as there are set bits, so it's good when value is expected to
have few nonzero bits.
The method was first proposed by Peter Wegner (in CACM 3 / 322 - 1960) and it's well known
since it appears in C Programming Language by Brian W. Kernighan and Dennis M. Ritchie.
unsigned popcount(std::uint64_t x)
{
const std::uint64_t m1 = 0x5555555555555555; // binary: 0101...
const std::uint64_t m2 = 0x3333333333333333; // binary: 00110011..
const std::uint64_t m4 = 0x0f0f0f0f0f0f0f0f; // binary: 0000111100001111
https://riptutorial.com/ 49
x -= (x >> 1) & m1; // put count of each 2 bits into those 2 bits
x = (x & m2) + ((x >> 2) & m2); // put count of each 4 bits into those 4 bits
x = (x + (x >> 4)) & m4; // put count of each 8 bits into those 8 bits
return (x * h01) >> 56; // left 8 bits of x + (x<<8) + (x<<16) + (x<<24) + ...
}
This kind of implementation has the best worst-case behavior (see Hamming weight for further
details).
Many CPUs have a specific instruction (like x86's popcnt) and the compiler could offer a specific (
non standard) built in function. E.g. with g++ there is:
The n & (n - 1) trick (see Remove rightmost set bit) is also useful to determine if an integer is a
power of 2:
Note that without the first part of the check (n &&), 0 is incorrectly considered a power of 2.
One of several applications of bit manipulation is converting a letter from small to capital or vice
versa by choosing a mask and a proper bit operation. For example, the a letter has this binary
representation 01(1)00001 while its capital counterpart has 01(0)00001. They differ solely in the bit in
parenthesis. In this case, converting the a letter from small to capital is basically setting the bit in
parenthesis to one. To do so, we do the following:
/****************************************
convert small letter to captial letter.
========================================
a: 01100001
mask: 11011111 <-- (0xDF) 11(0)11111
:---------
a&mask: 01000001 <-- A letter
*****************************************/
#include <cstdio>
int main()
{
char op1 = 'a'; // "a" letter (i.e. small case)
int mask = 0xDF; // choosing a proper mask
https://riptutorial.com/ 50
printf("a (AND) mask = A\n");
printf("%c & 0xDF = %c\n", op1, op1 & mask);
return 0;
}
The result is
https://riptutorial.com/ 51
Chapter 13: Bit Operators
Remarks
Bit shift operations are not portable across all processor architectures, different processors can
have different bit-widths. In other words, if you wrote
int a = ~0;
int b = a << 1;
This value would be different on a 64 bit machine vs. on a 32 bit machine, or from an x86 based
processor to a PIC based processor.
Endian-ness does not need to be taken into account for the bit wise operations themselves, that is,
the right shift (>>) will shift the bits towards the least significant bit and an XOR will perform an
exclusive or on the bits. Endian-ness only needs to be taken into account with the data itself, that
is, if endian-ness is a concern for your application, it's a concern regardless of bit wise operations.
Examples
& - bitwise AND
std::cout << "a = " << a << ", b = " << b << ", c = " << c << std::endl;
Output
a = 6, b = 10, c = 2
Why
A bit wise AND operates on the bit level and uses the following Boolean truth table:
When the binary value for a (0110) and the binary value for b (1010) are AND'ed together we get the
binary value of 0010:
int a = 0 1 1 0
int b = 1 0 1 0 &
---------
int c = 0 0 1 0
https://riptutorial.com/ 52
The bit wise AND does not change the value of the original values unless specifically assigned to
using the bit wise assignment compound operator &=:
| - bitwise OR
std::cout << "a = " << a << ", b = " << b << ", c = " << c << std::endl;
Output
a = 5, b = 12, c = 13
Why
A bit wise OR operates on the bit level and uses the following Boolean truth table:
When the binary value for a (0101) and the binary value for b (1100) are OR'ed together we get the
binary value of 1101:
int a = 0 1 0 1
int b = 1 1 0 0 |
---------
int c = 1 1 0 1
The bit wise OR does not change the value of the original values unless specifically assigned to
using the bit wise assignment compound operator |=:
std::cout << "a = " << a << ", b = " << b << ", c = " << c << std::endl;
Output
a = 5, b = 9, c = 12
https://riptutorial.com/ 53
Why
A bit wise XOR (exclusive or) operates on the bit level and uses the following Boolean truth table:
Notice that with an XOR operation true OR true = false where as with operations true AND/OR true
= true, hence the exclusive nature of the XOR operation.
Using this, when the binary value for a (0101) and the binary value for b (1001) are XOR'ed together
we get the binary value of 1100:
int a = 0 1 0 1
int b = 1 0 0 1 ^
---------
int c = 1 1 0 0
The bit wise XOR does not change the value of the original values unless specifically assigned to
using the bit wise assignment compound operator ^=:
The bit wise XOR can be utilized in many ways and is often utilized in bit mask operations for
encryption and compression.
Note: The following example is often shown as an example of a nice trick. But should not be used
in production code (there are better ways std::swap() to achieve the same result).
You can also utilize an XOR operation to swap two variables without a temporary:
int a = 42;
int b = 64;
// XOR swap
a ^= b;
b ^= a;
a ^= b;
std::cout << "a = " << a << ", b = " << b << "\n";
To productionalize this you need to add a check to make sure it can be used.
https://riptutorial.com/ 54
a ^= b;
b ^= a;
a ^= b;
}
}
So though it looks like a nice trick in isolation it is not useful in real code. xor is not a base logical
operation,but a combination of others: a^c=~(a&c)&(a|c)
int cn=0b0111;
Output
a = 234, b = 21
Why
A bit wise NOT (unary complement) operates on the bit level and simply flips each bit. If it's a 1, it's
changed to a 0, if it's a 0, it's changed to a 1. The bit wise NOT has the same effect as XOR'ing a
value against the max value for a specific type:
The bit wise NOT can also be a convenient way to check the maximum value for a specific integral
type:
The bit wise NOT does not change the value of the original value and does not have a compound
assignment operator, so you can not do a ~= 10 for example.
The bit wise NOT (~) should not be confused with the logical NOT (!); where a bit wise NOT will
flip each bit, a logical NOT will use the whole value to do its operation on, in other words (!1) !=
(~1)
https://riptutorial.com/ 55
<< - left shift
int a = 1; // 0001b
int b = a << 1; // 0010b
std::cout << "a = " << a << ", b = " << b << std::endl;
Output
a = 1, b = 2
Why
The left bit wise shift will shift the bits of the left hand value (a) the number specified on the right (1
), essentially padding the least significant bits with 0's, so shifting the value of 5 (binary 0000 0101)
to the left 4 times (e.g. 5 << 4) will yield the value of 80 (binary 0101 0000). You might note that
shifting a value to the left 1 time is also the same as multiplying the value by 2, example:
int a = 7;
while (a < 200) {
std::cout << "a = " << a << std::endl;
a <<= 1;
}
a = 7;
while (a < 200) {
std::cout << "a = " << a << std::endl;
a *= 2;
}
But it should be noted that the left shift operation will shift all bits to the left, including the sign bit,
example:
int a = 2147483647; // 0111 1111 1111 1111 1111 1111 1111 1111
int b = a << 1; // 1111 1111 1111 1111 1111 1111 1111 1110
std::cout << "a = " << a << ", b = " << b << std::endl;
While some compilers will yield results that seem expected, it should be noted that if you left shift
a signed number so that the sign bit is affected, the result is undefined. It is also undefined if the
number of bits you wish to shift by is a negative number or is larger than the number of bits the
type on the left can hold, example:
int a = 1;
int b = a << -1; // undefined behavior
char c = a << 20; // undefined behavior
The bit wise left shift does not change the value of the original values unless specifically assigned
to using the bit wise assignment compound operator <<=:
https://riptutorial.com/ 56
int a = 5; // 0101b
a <<= 1; // a = a << 1;
int a = 2; // 0010b
int b = a >> 1; // 0001b
std::cout << "a = " << a << ", b = " << b << std::endl;
Output
a = 2, b = 1
Why
The right bit wise shift will shift the bits of the left hand value (a) the number specified on the right (
1); it should be noted that while the operation of a right shift is standard, what happens to the bits
of a right shift on a signed negative number is implementation defined and thus cannot be
guaranteed to be portable, example:
int a = -2;
int b = a >> 1; // the value of b will be depend on the compiler
It is also undefined if the number of bits you wish to shift by is a negative number, example:
int a = 1;
int b = a >> -1; // undefined behavior
The bit wise right shift does not change the value of the original values unless specifically
assigned to using the bit wise assignment compound operator >>=:
int a = 2; // 0010b
a >>= 1; // a = a >> 1;
https://riptutorial.com/ 57
Chapter 14: Build Systems
Introduction
C++, like C, has a long and varied history regarding compilation workflows and build processes.
Today, C++ has various popular build systems that are used to compile programs, sometimes for
multiple platforms within one build system. Here, a few build systems will be reviewed and
analyzed.
Remarks
Currently, there exists no universal or dominant build system for C++ that is both popular and
cross-platform. However, there do exist several major build systems that are attached to major
platforms/projects, the most notable being GNU Make with the GNU/Linux operating system and
NMAKE with the Visual C++/Visual Studio project system.
Additionally, some Integrated Development Environments (IDEs) also include specialized build
systems to be used specifically with the native IDE. Certain build system generators can generate
these native IDE build system/project formats, such as CMake for Eclipse and Microsoft Visual
Studio 2012.
Examples
Generating Build Environment with CMake
CMake generates build environments for nearly any compiler or IDE from a single project
definition. The following examples will demonstrate how to add a CMake file to the cross-platform
"Hello World" C++ code.
CMake files are always named "CMakeLists.txt" and should already exist in every project's root
directory (and possibly in sub-directories too.) A basic CMakeLists.txt file looks like:
cmake_minimum_required(VERSION 2.4)
project(HelloWorld)
add_executable(HelloWorld main.cpp)
This file tells CMake the project name, what file version to expect, and instructions to generate an
executable called "HelloWorld" that requires main.cpp.
Generate a build environment for your installed compiler/IDE from the command line:
> cmake .
https://riptutorial.com/ 58
Build the application with:
This generates the default build environment for the system, depending on the OS and installed
tools. Keep source code clean from any build artifacts with use of "out-of-source" builds:
CMake can also abstract the platform shell's basic commands from the previous example:
CMake includes generators for a number of common build tools and IDEs. To generate makefiles
for Visual Studio's nmake:
Introduction
The GNU Make (styled make) is a program dedicated to the automation of executing shell
commands. GNU Make is one specific program that falls under the Make family. Make remains
popular among Unix-like and POSIX-like operating systems, including those derived from the
Linux kernel, Mac OS X, and BSD.
GNU Make is especially notable for being attached to the GNU Project, which is attached to the
popular GNU/Linux operating system. GNU Make also has compatible versions running on various
flavors of Windows and Mac OS X. It is also a very stable version with historical significance that
remains popular. It is for these reasons that GNU Make is often taught alongside C and C++.
Basic rules
To compile with make, create a Makefile in your project directory. Your Makefile could be as
simple as:
Makefile
https://riptutorial.com/ 59
# First, we set the compiler to be g++
CXX=g++
# Then, we say that we want to compile with g++'s recommended warnings and some extra ones.
CXXFLAGS=-Wall -Wextra -pedantic
SRCS=main.cpp
# When you call `make` at the command line, this "target" is called.
# The $(EXE) at the right says that the `all` target depends on the `$(EXE)` target.
# $(EXE) expands to be the content of the EXE variable
# Note: Because this is the first target, it becomes the default target if `make` is called
without target
all: $(EXE)
NOTE: Make absolutely sure that the indentations are with a tab, not with four
spaces. Otherwise, you'll get an error of Makefile:10: *** missing separator. Stop.
$ cd ~/Path/to/project
$ make
$ ls
app main.cpp Makefile
$ ./app
Hello World!
$ make clean
$ ls
main.cpp Makefile
Incremental builds
When you start having more files, make becomes more useful. What if you edited a.cpp but not
b.cpp? Recompiling b.cpp would take more time.
https://riptutorial.com/ 60
With the following directory structure:
.
+-- src
| +-- a.cpp
| +-- a.hpp
| +-- b.cpp
| +-- b.hpp
+-- Makefile
Makefile
CXX=g++
CXXFLAGS=-Wall -Wextra -pedantic
EXE=app
SRCS_GLOB=src/*.cpp
SRCS=$(wildcard $(SRCS_GLOB))
OBJS=$(SRCS:.cpp=.o)
all: $(EXE)
$(EXE): $(OBJS)
@$(CXX) -o $@ $(OBJS)
depend: .depend
.depend: $(SRCS)
@-rm -f ./.depend
@$(CXX) $(CXXFLAGS) -MM $^>>./.depend
clean:
-rm -f $(EXE)
-rm $(OBJS)
-rm *~
-rm .depend
include .depend
Again watch the tabs. This new Makefile ensures that you only recompile changed files,
minimizing compile time.
Documentation
For more on make, see the official documentation by the Free Software Foundation, the
stackoverflow documentation and dmckee's elaborate answer on stackoverflow.
You can build the cross-platform "Hello World" C++ code, using Scons - A Python-language
software construction tool.
https://riptutorial.com/ 61
First, create a file called SConstruct (note that SCons will look for a file with this exact name by
default). For now, the file should be in a directory right along your hello.cpp. Write in the new file
the line
Program('hello.cpp')
Now, from the terminal, run scons. You should see something like
$ scons
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
g++ -o hello.o -c hello.cpp
g++ -o hello hello.o
scons: done building targets.
(although the details will vary depending on your operating system and installed compiler).
The Environment and Glob classes will help you further configure what to build. E.g., the SConstruct
file
env=Environment(CPPPATH='/usr/include/boost/',
CPPDEFINES=[],
LIBS=[],
SCONS_CXX_STANDARD="c++11"
)
env.Program('hello', Glob('src/*.cpp'))
builds the executable hello, using all cpp files in src. Its CPPPATH is /usr/include/boost and it
specifies the C++11 standard.
Ninja
Introduction
The Ninja build system is described by its project website as "a small build system with a focus on
speed." Ninja is designed to have its files generated by build system file generators, and takes a
low-level approach to build systems, in contrast to higher-level build system managers like CMake
or Meson.
Ninja is primarily written in C++ and Python, and was created as an alternative to the SCons build
system for the Chromium project.
Introduction
https://riptutorial.com/ 62
NMAKE is a command-line utility developed by Microsoft to be used primarily in conjunction with
Microsoft Visual Studio and/or the Visual C++ command line tools.
NMAKE is build system that falls under the Make family of build systems, but has certain distinct
features that diverge from Unix-like Make programs, such as supporting Windows-specific file path
syntax (which itself differs from Unix-style file paths).
Autotools (GNU)
Introduction
The Autotools are a group of programs that create a GNU Build System for a given software
package. It is a suite of tools that work together to produce various build resources, such as a
Makefile (to be used with GNU Make). Thus, Autotools can be considered a de facto build system
generator.
• Autoconf
• Automake (not to be confused with make)
In general, Autotools is meant to generate the Unix-compatible script and Makefile to allow the
following command to build (as well as install) most packages (in the simple case):
As such, Autotools also has a relationship with certain package managers, especially those that
are attached to operating systems that conform to the POSIX Standard(s).
https://riptutorial.com/ 63
Chapter 15: C incompatibilities
Introduction
This describes what C code will break in a C++ compiler.
Examples
Reserved Keywords
The first example are keywords that have a special purpose in C++: the following is legal in C, but
not C++.
int class = 5
In C, pointers can be cast to a void*, which needs an explicit cast in C++. The following is illegal in
C++, but legal in C:
void* ptr;
int* intptr = ptr;
Adding an explicit cast makes this work, but can cause further issues.
goto or switch
In C++, you may not skip initializations with goto or switch. The following is valid in C, but not C++:
goto foo;
int skipped = 1;
foo;
https://riptutorial.com/ 64
Chapter 16: C++ Containers
Introduction
C++ containers store a collection of elements. Containers include vectors, lists, maps, etc. Using
Templates, C++ containers contain collections of primitives (e.g. ints) or custom classes (e.g.
MyClass).
Examples
C++ Containers Flowchart
Choosing which C++ Container to use can be tricky, so here's a simple flowchart to help decide
which Container is right for the job.
https://riptutorial.com/ 65
https://riptutorial.com/ 66
Megan Hopkins
https://riptutorial.com/ 67
Chapter 17: C++ Debugging and Debug-
prevention Tools & Techniques
Introduction
A lot of time from C++ developers is spent debugging. This topic is meant to assist with this task
and give inspiration for techniques. Don't expect an extensive list of issues and solutions fixed by
the tools or a manual on the mentioned tools.
Remarks
This topic ain't complete yet, examples on following techniques/tools would be useful:
Examples
My C++ program ends with segfault - valgrind
#include <iostream>
void fail() {
int *p1;
int *p2(NULL);
int *p3 = p1;
if (p3) {
std::cout << *p3 << std::endl;
}
}
int main() {
fail();
}
Run:
$ ./main
https://riptutorial.com/ 68
Segmentation fault (core dumped)
$
$ valgrind ./main
==8515== Memcheck, a memory error detector
==8515== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==8515== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==8515== Command: ./main
==8515==
==8515== Conditional jump or move depends on uninitialised value(s)
==8515== at 0x400813: fail() (main.cpp:7)
==8515== by 0x40083F: main (main.cpp:13)
==8515==
==8515== Invalid read of size 4
==8515== at 0x400819: fail() (main.cpp:8)
==8515== by 0x40083F: main (main.cpp:13)
==8515== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==8515==
==8515==
==8515== Process terminating with default action of signal 11 (SIGSEGV): dumping core
==8515== Access not within mapped region at address 0x0
==8515== at 0x400819: fail() (main.cpp:8)
==8515== by 0x40083F: main (main.cpp:13)
==8515== If you believe this happened as a result of a stack
==8515== overflow in your program's main thread (unlikely but
==8515== possible), you can try to increase the size of the
==8515== main thread stack using the --main-stacksize= flag.
==8515== The main thread stack size used in this run was 8388608.
==8515==
==8515== HEAP SUMMARY:
==8515== in use at exit: 72,704 bytes in 1 blocks
==8515== total heap usage: 1 allocs, 0 frees, 72,704 bytes allocated
==8515==
==8515== LEAK SUMMARY:
==8515== definitely lost: 0 bytes in 0 blocks
==8515== indirectly lost: 0 bytes in 0 blocks
==8515== possibly lost: 0 bytes in 0 blocks
==8515== still reachable: 72,704 bytes in 1 blocks
==8515== suppressed: 0 bytes in 0 blocks
==8515== Rerun with --leak-check=full to see details of leaked memory
==8515==
==8515== For counts of detected and suppressed errors, rerun with: -v
==8515== Use --track-origins=yes to see where uninitialised values come from
==8515== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
$
The first line tells us that segfault is caused by reading 4 bytes. The second and the third lines are
call stack. It means that the invalid read is performed at the fail() function, line 8 of main.cpp,
https://riptutorial.com/ 69
which is called by main, line 13 of main.cpp.
But we check the pointer first, so what's wrong? Lets check the other block:
if (p3) {
Which points us to the line where we check p3 instead of p2. But how is it possible that p3 is
uninitialized? We initialize it by:
The argument for valgrind is just after valgrind. If we put it after our program, it would be passed to
our program.
Which tells us that the uninitialized value we used at line 7 was created at line 3:
int *p1;
#include <iostream>
void fail() {
https://riptutorial.com/ 70
int *p1;
int *p2(NULL);
int *p3 = p1;
if (p3) {
std::cout << *p2 << std::endl;
}
}
int main() {
fail();
}
gdb ./main
(gdb) run
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/opencog/code-snippets/stackoverflow/a.out
We see the segmentation fault is happening at line 11. So the only variable being used at this line
is pointer p2. Lets examine its content typing print.
(gdb) print p2
$1 = (int *) 0x0
Now we see that p2 was initialized to 0x0 which stands for NULL. At this line, we know that we are
trying to dereference a NULL pointer. So we go and fix it.
Clean code
Debugging starts with understanding the code you are trying to debug.
Bad code:
int main() {
int value;
std::vector<int> vectorToSort;
vectorToSort.push_back(42); vectorToSort.push_back(13);
for (int i = 52; i; i = i - 1)
{
https://riptutorial.com/ 71
vectorToSort.push_back(i *2);
}
/// Optimized for sorting small vectors
if (vectorToSort.size() == 1);
else
{
if (vectorToSort.size() <= 2)
std::sort(vectorToSort.begin(), std::end(vectorToSort));
}
for (value : vectorToSort) std::cout << value << ' ';
return 0; }
Better code:
std::vector<int> createSemiRandomData() {
std::vector<int> data;
data.push_back(42);
data.push_back(13);
for (int i = 52; i; --i)
vectorToSort.push_back(i *2);
return data;
}
std::sort(vectorToSort.begin(), vectorToSort.end());
}
int main() {
auto vectorToSort = createSemiRandomData();
sortVector(std::ref(vectorToSort));
printVector(vectorToSort);
return 0;
}
Regardless of the coding styles you prefer and use, having a consistent coding (and formatting)
style will help you understanding the code.
Looking at the code above, one can identify a couple of improvements to improve readability and
debuggability:
https://riptutorial.com/ 72
of the data and only want to step into the sorting.
Another advantage is that you need to read less code (and memorize it) while stepping through
the code. You now only need to read 3 lines of code in main() in order to understand it, instead of
the whole function.
The third advantage is that you simply have less code to look at, which helps a trained eye in
spotting this bug within seconds.
As formatting code is time consuming task, it is recommended to use a dedicated tool for this.
Most IDEs have at least some kind of support for this and can do formatting more consistent than
humans.
You might note that the style is not limited to spaces and newlines as we no longer mix the free-
style and the member functions to get begin/end of the container. (v.begin() vs std::end(v)).
Conclusion
Having clean code will help you understanding the code and will reduce the time you need to
debug it. In the second example, a code reviewer might even spot the bug at first glance, while the
bug might be hidden in the details in the first one. (PS: The bug is in the compare with 2.)
Static analysis
Static analysis is the technique in which on checks the code for patterns linked to known bugs.
Using this technique is less time consuming than a code review, though, its checks are only limited
to those programmed in the tool.
Checks can include the incorrect semi-colon behind the if-statement (if (var);) till advanced
graph algorithms which determine if a variable is not initialized.
https://riptutorial.com/ 73
Compiler warnings
Enabling static analysis is easy, the most simplistic version is already build-in in your compiler:
If you enable these options, you will notice that each compiler will find bugs the others don't and
that you will get errors on techniques which might be valid or valid in a specific context. while
(staticAtomicBool); might be acceptable even if while (localBool); ain't.
So unlike code review, you are fighting a tool which understands your code, tells you a lot of useful
bugs and sometimes disagrees with you. In this last case, you might have to suppress the warning
locally.
As the options above enable all warnings, they might enable warnings you don't want. (Why
should your code be C++98 compatible?) If so, you can simply disable that specific warning:
Where compiler warnings assist you during development, they slow down compilation quite a bit.
That is why you might not always want to enable them by default. Either you run them by default
or you enable some continuous integration with the more expensive checks (or all of them).
External tools
If you decide to have some continuous integration, the use of other tools ain't such a stretch. A
tool like clang-tidy has an list of checks which covers a wide range of issues, some examples:
• Actual bugs
Prevention of slicing
○
• Readability checks
Misleading indentation
○
• Modernization checks
Use make_unique()
○
Use nullptr
○
• Performance checks
Find unneeded copies
○
The list might not be that large, as Clang already has a lot of compiler warnings, however it will
bring you one step closer to a high quality code base.
https://riptutorial.com/ 74
Other tools
Other tools with similar purpose exist, like:
Conclusion
A lot static analysis tools exist for C++, both build-in in the compiler as external tools. Trying them
out doesn't take that much time for easy setups and they will find bugs you might miss in code
review.
Stack corruptions are annoying bugs to look at. As the stack is corrupted, the debugger often can't
give you a good stack trace of where you are and how you got there.
This is where safe-stack comes into play. Instead of using a single stack for your threads, it will
use two: A safe stack and a dangerous stack. The safe stack works exactly like it did before,
except that some parts are moved to the dangerous stack.
As a result, any operation you do with those pointers, any modification you make on the memory
(based on those pointers/references) can only effect the memory in the second stack. As one
never gets a pointer which is close to the safe stack, the stack cannot corrupt the stack and the
debugger can still read all functions on the stack to give a nice trace.
For this reason, the feature has been activated on chromium and has been reported to have a
<1% CPU overhead.
https://riptutorial.com/ 75
Right now, the option is only available in the clang compiler, where one can pass -fsanitize=safe-
stack to the compiler. A proposal was made to implement the same feature in GCC.
Conclusion
Stack corruptions can become easier to debug when safe stack is enabled. Due to a low
performance overhead, you can even activated by default in your build configuration.
https://riptutorial.com/ 76
Chapter 18: C++ function "call by value" vs.
"call by reference"
Introduction
The scope of this section is to explain the differences in theory and implementation for what
happens with the parameters of a function upon calling.
In detail the parameters can be seen as variables before the function call and inside the function,
where the visible behaviour and accessibility to these variables differs with the method used to
hand them over.
Additionally, the reusability of variables and their respective values after the function call also is
explained by this topic.
Examples
Call by value
Upon calling a function there are new elements created on the program stack. These include
some information about the function and also space (memory locations) for the parameters and
the return value.
When handing over a parameter to a function the value of the used variable (or literal) is copied
into the memory location of the function parameter. This implies that now there a two memory
locations with the same value. Inside of the function we only work on the parameter memory
location.
After leaving the function the memory on the program stack is popped (removed) which erases all
data of the function call, including the memory location of the parameters we used inside. Thus,
the values changed inside the function do not affect the outside variables values.
int main(void) {
int a = 0;
int b = 1; //outer_b
int c;
https://riptutorial.com/ 77
c = func(a,b);
//the return value is copied to c
In this code we create variables inside the main function. These get assigned values. Upon calling
the functions there are two new variables created: f and inner_b where b shares the name with the
outer variable it does not share the memory location. The behaviour of a<->f and b<->b is identical.
The following graphic symbolizes what is happening on the stack and why there is no change in
varibale b. The graphic is not fully accurate but emphazises the example.
It is called "call by value" because we do not hand over the variables but only the values of these
variables.
https://riptutorial.com/ 78
Chapter 19: C++ Streams
Remarks
Default constructor of std::istream_iterator constructs an iterator which represents the end of the
stream. Thus, std::copy(std::istream_iterator<int>(ifs), std::istream_iterator<int>(), ....
means to copy from the current position in ifs to the end.
Examples
String streams
std::ostringstream is a class whose objects look like an output stream (that is, you can write to
them via operator<<), but actually store the writing results, and provide them in the form of a
stream.
#include <sstream>
#include <string>
int main()
{
ostringstream ss;
ss << "the answer to everything is " << 42;
const string result = ss.str();
}
The line
ostringstream ss;
creates such an object. This object is first manipulated like a regular stream:
Following that, though, the resulting stream can be obtained like this:
This is mainly useful when we have a class for which stream serialization has been defined, and
for which we want a string form. For example, suppose we have some class
https://riptutorial.com/ 79
class foo
{
// All sort of stuff here.
};
foo f;
we could use
ostringstream ss;
ss << f;
const string result = ss.str();
ifstreamhas operator bool(), which returns true when a stream has no errors and is ready to read.
Moreover, ifstream::operator >> returns a reference to the stream itself, so we can read and check
for EOF (as well as for errors) in one line with very elegant syntax:
std::ifstream ifs("1.txt");
std::string s;
while(ifs >> s) {
std::cout << s << std::endl;
}
https://riptutorial.com/ 80
while(std::getline(ifs, s)) {
std::cout << s << std::endl;
}
Obviously, std::getline should also be used for reading a single-line file till the end.
s.resize(100);
std::copy(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>(),
s.begin());
Otherwise, we need to insert each character to the end of the string, so std::back_inserter is what
we need:
std::copy(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>(),
std::back_inserter(s));
Alternatively, it is possible to initialize a collection with stream data, using a constructor with
iterator range arguments:
std::vector v(std::istreambuf_iterator<char>(ifs),
std::istreambuf_iterator<char>());
Note that these examples are also applicable if ifs is opened as binary file:
Copying streams
A file may be copied to another file with streams and iterators:
std::ofstream ofs("out.file");
std::copy(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>(),
std::ostream_iterator<char>(ofs));
ofs.close();
or redirected to any other type of stream with a compatible interface. For example Boost.Asio
network stream:
boost::asio::ip::tcp::iostream stream;
stream.connect("example.com", "http");
https://riptutorial.com/ 81
std::copy(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>(),
std::ostream_iterator<char>(stream));
stream.close();
Arrays
As iterators might be thought of as a generalization of pointers, STL containers in the examples
above may be replaced with native arrays. Here is how to parse numbers into array:
int arr[100];
std::copy(std::istream_iterator<char>(ifs), std::istream_iterator<char>(), arr);
Beware of buffer overflow, as arrays cannot be resized on-the-fly after they were allocated. For
example, if the code above will be fed with a file that contains more than 100 integer numbers, it
will attempt to write outside the array and run into undefined behavior.
Basic printing
std::ostream_iterator allows to print contents of an STL container to any output stream without
explicit loops. The second argument of std::ostream_iterator constructor sets the delimiter. For
example, the following code:
std::vector<int> v = {1,2,3,4};
std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " ! "));
will print
1 ! 2 ! 3 ! 4 !
and instantiate std::ostream_iterator with float, while the contained values remain int:
std::vector<int> v = {1,2,3,4};
std::copy(v.begin(), v.end(), std::ostream_iterator<float>(std::cout, " ! "));
https://riptutorial.com/ 82
so the code above yields
std::vector<int> v = {1,2,3,4,8,16};
we can easily print boolean value of "x is even" statement for each element:
Arrays
As in the section about reading text files, almost all these considerations may be applied to native
arrays. For example, let's print squared values from a native array:
Parsing files
https://riptutorial.com/ 83
Parsing files into STL containers
istream_iteratorsare very useful for reading sequences of numbers or other parsable data into
STL containers without explicit loops in the code.
std::vector<int> v(100);
std::copy(std::istream_iterator<int>(ifs), std::istream_iterator<int>(),
v.begin());
std::vector<int> v;
std::copy(std::istream_iterator<int>(ifs), std::istream_iterator<int>(),
std::back_inserter(v));
Note that the numbers in the input file may be divided by any number of any whitespace
characters and newlines.
std::string s;
double a, b;
while(ifs >> a >> b >> s) {
std::cout << a << " " << b << " " << s << std::endl;
}
Transformation
Any range-manipulating function may be used with std::istream_iterator ranges. One of them is
std::transform, which allows to process data on-the-fly. For example, let's read integer values,
multiply them by 3.14 and store the result into floating-point container:
std::vector<double> v(100);
std::transform(std::istream_iterator<int>(ifs), std::istream_iterator<int>(),
v.begin(),
https://riptutorial.com/ 84
[](int val) {
return val * 3.14;
});
https://riptutorial.com/ 85
Chapter 20: C++11 Memory Model
Remarks
Different threads trying to access the same memory location participate in a data race if at least
one of the operations is a modification (also known as store operation). These data races cause
undefined behavior. To avoid them one needs to prevent these threads from concurrently
executing such conflicting operations.
Synchronization primitives (mutex, critical section and the like) can guard such accesses. The
Memory Model introduced in C++11 defines two new portable ways to synchronize access to
memory in multi-threaded environment: atomic operations and fences.
Atomic Operations
It is now possible to read and write to given memory location by the use of atomic load and atomic
store operations. For convenience these are wrapped in the std::atomic<t> template class. This
class wraps a value of type t but this time loads and stores to the object are atomic.
The template is not available for all types. Which types are available is implementation specific,
but this usually includes most (or all) available integral types as well as pointer types. So that
std::atomic<unsigned> and std::atomic<std::vector<foo> *> should be available, while
std::atomic<std::pair<bool,char>> most probably wont be.
• All atomic operations can be performed concurrently from multiple threads without causing
undefined behavior.
• An atomic load will see either the initial value which the atomic object was constructed with,
or the value written to it via some atomic store operation.
• Atomic stores to the same atomic object are ordered the same in all threads. If a thread has
already seen the value of some atomic store operation, subsequent atomic load operations
will see either the same value, or the value stored by subsequent atomic store operation.
• Atomic read-modify-write operations allow atomic load and atomic store to happen without
other atomic store in between. For example one can atomically increment a counter from
multiple threads, and no increment will be lost regardless of the contention between the
threads.
• Atomic operations receive an optional std::memory_order parameter which defines what
additional properties the operation has regarding other memory locations.
std::memory_order Meaning
https://riptutorial.com/ 86
std::memory_order Meaning
These memory order tags allow three different memory ordering disciplines: sequential
consistency, relaxed, and release-acquire with its sibling release-consume.
Sequential Consistency
If no memory order is specified for an atomic operation, the order defaults to sequential
consistency. This mode can also be explicitly selected by tagging the operation with
std::memory_order_seq_cst.
With this order no memory operation can cross the atomic operation. All memory operations
sequenced before the atomic operation happen before the atomic operation and the atomic
operation happens before all memory operations that are sequenced after it. This mode is
probably the easiest one to reason about but it also leads to the greatest penalty to performance.
It also prevents all compiler optimizations that might otherwise try to reorder operations past the
atomic operation.
Relaxed Ordering
The opposite to sequential consistency is the relaxed memory ordering. It is selected with the
std::memory_order_relaxed tag. Relaxed atomic operation will impose no restrictions on other
memory operations. The only effect that remains, is that the operation is itself still atomic.
Release-Acquire Ordering
An atomic store operation can be tagged with std::memory_order_release and an atomic load
operation can be tagged with std::memory_order_acquire. The first operation is called (atomic)
store-release while the second is called (atomic) load-acquire.
When load-acquire sees the value written by a store-release the following happens: all store
operations sequenced before the store-release become visible to (happen before) load operations
that are sequenced after the load-acquire.
Atomic read-modify-write operations can also receive the cumulative tag std::memory_order_acq_rel
. This makes the atomic load portion of the operation an atomic load-acquire while the atomic
store portion becomes atomic store-release.
The compiler is not allowed to move store operations after an atomic store-release operation. It is
https://riptutorial.com/ 87
also not allowed to move load operations before atomic load-acquire (or load-consume).
Also note that there is no atomic load-release or atomic store-acquire. Attempting to create such
operations makes them relaxed operations.
Release-Consume Ordering
This combination is similar to release-acquire, but this time the atomic load is tagged with
std::memory_order_consume and becomes (atomic) load-consume operation. This mode is the same
as release-acquire with the only difference that among the load operations sequenced after the
load-consume only these depending on the value loaded by the load-consume are ordered.
Fences
Fences also allow memory operations to be ordered between threads. A fence is either a release
fence or acquire fence.
If a release fence happens before an acquire fence, then stores sequenced before the release
fence are visible to loads sequenced after the acquire fence. To guarantee that the release fence
happens before the acquire fence one may use other synchronization primitives including relaxed
atomic operations.
Examples
Need for Memory Model
int x, y;
bool ready = false;
void init()
{
x = 2;
y = 3;
ready = true;
}
void use()
{
if (ready)
std::cout << x + y;
}
One thread calls the init() function while another thread (or signal handler) calls the use()
function. One might expect that the use() function will either print 5 or do nothing. This may not
always be the case for several reasons:
• The CPU may reorder the writes that happen in init() so that the code that actually
executes might look like:
https://riptutorial.com/ 88
void init()
{
ready = true;
x = 2;
y = 3;
}
• The CPU may reorder the reads that happen in use() so that the actually executed code
might become:
void use()
{
int local_x = x;
int local_y = y;
if (ready)
std::cout << local_x + local_y;
}
• An optimizing C++ compiler may decide to reorder the program in similar way.
Such reordering cannot change the behavior of a program running in single thread because a
thread cannot interleave the calls to init() and use(). On the other hand in a multi-threaded
setting one thread may see part of the writes performed by the other thread where it may happen
that use() may see ready==true and garbage in x or y or both.
The C++ Memory Model allows the programmer to specify which reordering operations are
permitted and which are not, so that a multi-threaded program would also be able to behave as
expected. The example above can be rewritten in thread-safe way like this:
int x, y;
std::atomic<bool> ready{false};
void init()
{
x = 2;
y = 3;
ready.store(true, std::memory_order_release);
}
void use()
{
if (ready.load(std::memory_order_acquire))
std::cout << x + y;
}
Here init() performs atomic store-release operation. This not only stores the value true into ready,
but also tells the compiler that it cannot move this operation before write operations that are
sequenced before it.
The use() function does an atomic load-acquire operation. It reads the current value of ready and
also forbids the compiler from placing read operations that are sequenced after it to happen before
the atomic load-acquire.
These atomic operations also cause the compiler to put whatever hardware instructions are
https://riptutorial.com/ 89
needed to inform the CPU to refrain from the unwanted reorderings.
Because the atomic store-release is to the same memory location as the atomic load-acquire, the
memory model stipulates that if the load-acquire operation sees the value written by the store-
release operation, then all writes performed by init()'s thread prior to that store-release will be
visible to loads that use()'s thread executes after its load-acquire. That is if use() sees ready==true,
then it is guaranteed to see x==2 and y==3.
Note that the compiler and the CPU are still allowed to write to y before writing to x, and similarly
the reads from these variables in use() can happen in any order.
Fence example
The example above can also be implemented with fences and relaxed atomic operations:
int x, y;
std::atomic<bool> ready{false};
void init()
{
x = 2;
y = 3;
atomic_thread_fence(std::memory_order_release);
ready.store(true, std::memory_order_relaxed);
}
void use()
{
if (ready.load(std::memory_order_relaxed))
{
atomic_thread_fence(std::memory_order_acquire);
std::cout << x + y;
}
}
If the atomic load operation sees the value written by the atomic store then the store happens
before the load, and so do the fences: the release fence happens before the acquire fence making
the writes to x and y that precede the release fence to become visible to the std::cout statement
that follows the acquire fence.
A fence might be beneficial if it can reduce the overall number of acquire, release or other
synchronization operations. For example:
void block_and_use()
{
while (!ready.load(std::memory_order_relaxed))
;
atomic_thread_fence(std::memory_order_acquire);
std::cout << x + y;
}
The block_and_use() function spins until the ready flag is set with the help of relaxed atomic load.
Then a single acquire fence is used to provide the needed memory ordering.
https://riptutorial.com/ 90
Read C++11 Memory Model online: https://riptutorial.com/cplusplus/topic/7975/cplusplus11-
memory-model
https://riptutorial.com/ 91
Chapter 21: Callable Objects
Introduction
Callable objects are the collection of all C++ structures which can be used as a function. In
practice, this are all things you can pass to the C++17 STL function invoke() or which can be used
in the constructor of std::function, this includes: Function pointers, Classes with operator(),
Classes with implicit conversions, References to functions, Pointers to member functions, Pointers
to member data, lambdas. The callable objects are used in many STL algorithms as predicate.
Remarks
A very useful talk by Stephan T. Lavavej (<functional>: What's New, And Proper Use) (Slides)
leads to the base of this documentation.
Examples
Function Pointers
Function pointers are the most basic way of passing functions around, which can also be used in
C. (See the C documentation for more details).
For the purpose of callable objects, a function pointer can be defined as:
If we would be using a function pointer for writing our own vector sort, it would look like:
struct GreaterThanInt {
static bool cmp(int lhs, int rhs) { return lhs > rhs; }
};
https://riptutorial.com/ 92
sortVectorInt(vectorOfInt, &GreaterThanInt::cmp); // Passes the pointer to a static member
function
Alternatively, we could have invoked the function pointer one of following ways:
Every class which overloads the operator() can be used as a function object. These classes can
be written by hand (often referred to as functors) or automatically generated by the compiler by
writing Lambdas from C++11 on.
struct Person {
std::string name;
unsigned int age;
};
As functors have their own identity, they cannot be put in a typedef and these have to be accepted
via template argument. The definition of std::find_if can look like:
From C++17 on, the calling of the predicate can be done with invoke: std::invoke(predicate, *i).
https://riptutorial.com/ 93
Chapter 22: Classes/Structures
Syntax
• variable.member_var = constant;
• variable.member_function();
• variable_pointer->member_var = constant;
• variable_pointer->member_function();
Remarks
Note that the only difference between the struct and class keywords is that by default, the
member variables, member functions, and base classes of a struct are public, while in a class
they are private. C++ programmers tend to call it a class if it has constructors and destructors, and
the ability to enforce its own invariants; or a struct if it's just a simple collection of values, but the
C++ language itself makes no distinction.
Examples
Class basics
A class is a user-defined type. A class is introduced with the class, struct or union keyword. In
colloquial usage, the term "class" usually refers only to non-union classes.
The class and struct keywords, called class keys, are largely interchangeable, except that the
default access specifier for members and bases is "private" for a class declared with the class key
and "public" for a class declared with the struct or union key (cf. Access modifiers).
struct Vector
{
int x;
int y;
int z;
};
// are equivalent to
class Vector
{
public:
https://riptutorial.com/ 94
int x;
int y;
int z;
};
By declaring a class` a new type is added to your program, and it is possible to instantiate objects
of that class by
Vector my_vector;
my_vector.x = 10;
my_vector.y = my_vector.x + 1; // my_vector.y = 11;
my_vector.z = my_vector.y - 4; // my:vector.z = 7;
Access specifiers
There are three keywords that act as access specifiers. These limit the access to class members
following the specifier, until another specifier changes the access level again:
Keyword Description
protected Only the class itself, derived classes and friends have access
When the type is defined using the class keyword, the default access specifier is private, but if the
type is defined using the struct keyword, the default access specifier is public:
MyStruct s;
s.x = 9; // well formed, because x is public
MyClass c;
c.x = 9; // ill-formed, because x is private
Access specifiers are mostly used to limit access to internal fields and methods, and force the
programmer to use a specific interface, for example to force use of getters and setters instead of
referencing a variable directly:
class MyClass {
public: /* Methods: */
https://riptutorial.com/ 95
void setX(int const x) noexcept { m_x = x; }
private: /* Fields: */
int m_x;
};
Using protected is useful for allowing certain functionality of the type to be only accessible to the
derived classes, for example, in the following code, the method calculateValue() is only accessible
to classes deriving from the base class Plus2Base, such as FortyTwo:
struct Plus2Base {
int value() noexcept { return calculateValue() + 2; }
protected: /* Methods: */
virtual int calculateValue() noexcept = 0;
};
struct FortyTwo: Plus2Base {
protected: /* Methods: */
int calculateValue() noexcept final override { return 40; }
};
Note that the friend keyword can be used to add access exceptions to functions or types for
accessing protected and private members.
The public, protected, and private keywords can also be used to grant or limit access to base
class subobjects. See the Inheritance example.
Inheritance
If a class/struct B inherits from a class/struct A, this means that B has as a parent A. We say that B is
a derived class/struct from A, and A is the base class/struct.
struct A
{
public:
int p1;
protected:
int p2;
private:
int p3;
};
• public
• private
https://riptutorial.com/ 96
• protected
Note that the default inheritance is the same as the default visibility of members: public if you use
the struct keyword, and private for the class keyword.
It's even possible to have a class derive from a struct (or vice versa). In this case, the default
inheritance is controlled by the child, so a struct that derives from a class will default to public
inheritance, and a class that derives from a struct will have private inheritance by default.
public inheritance:
B b;
b.p1 = 1; //well formed, p1 is public
b.p2 = 1; //ill formed, p2 is protected
b.p3 = 1; //ill formed, p3 is inaccessible
private inheritance:
struct B : private A
{
void foo()
{
p1 = 0; //well formed, p1 is private in B
p2 = 0; //well formed, p2 is private in B
p3 = 0; //ill formed, p3 is private in A
}
};
B b;
b.p1 = 1; //ill formed, p1 is private
b.p2 = 1; //ill formed, p2 is private
b.p3 = 1; //ill formed, p3 is inaccessible
protected inheritance:
struct B : protected A
{
void foo()
{
p1 = 0; //well formed, p1 is protected in B
p2 = 0; //well formed, p2 is protected in B
p3 = 0; //ill formed, p3 is private in A
}
};
B b;
https://riptutorial.com/ 97
b.p1 = 1; //ill formed, p1 is protected
b.p2 = 1; //ill formed, p2 is protected
b.p3 = 1; //ill formed, p3 is inaccessible
Note that although protected inheritance is allowed, the actual use of it is rare. One instance of
how protected inheritance is used in application is in partial base class specialization (usually
referred to as "controlled polymorphism").
When OOP was relatively new, (public) inheritance was frequently said to model an "IS-A"
relationship. That is, public inheritance is correct only if an instance of the derived class is also an
instance of the base class.
This was later refined into the Liskov Substitution Principle: public inheritance should only be used
when/if an instance of the derived class can be substituted for an instance of the base class under
any possible circumstance (and still make sense).
Private inheritance is typically said to embody a completely different relationship: "is implemented
in terms of" (sometimes called a "HAS-A" relationship). For example, a Stack class could inherit
privately from a Vector class. Private inheritance bears a much greater similarity to aggregation
than to public inheritance.
Protected inheritance is almost never used, and there's no general agreement on what sort of
relationship it embodies.
Virtual Inheritance
struct A{};
struct B: public virtual A{};
When class B has virtual base A it means that A will reside in most derived class of inheritance
tree, and thus that most derived class is also responsible for initializing that virtual base:
struct A
{
int member;
A(int param)
{
member = param;
}
};
struct B: virtual A
{
B(): A(5){}
};
struct C: B
{
C(): /*A(88)*/ {}
};
https://riptutorial.com/ 98
void f()
{
C object; //error since C is not initializing it's indirect virtual base `A`
}
If we un-comment /*A(88)*/ we won't get any error since C is now initializing it's indirect virtual
base A.
Also note that when we're creating variable object, most derived class is C, so C is responsible for
creating(calling constructor of) A and thus value of A::member is 88, not 5 (as it would be if we were
creating object of type B).
A A A
/ \ | |
B C B C
\ / \ /
D D
virtual inheritance normal inheritance
B and C both inherit from A, and D inherits from B and C, so there are 2 instances of A in D! This
results in ambiguity when you're accessing member of A through D, as the compiler has no way of
knowing from which class do you want to access that member (the one which B inherits, or the one
that is inherited byC?).
Virtual inheritance solves this problem: Since virtual base resides only in most derived object,
there will be only one instance of A in D.
struct A
{
void foo() {}
};
Multiple Inheritance
class A {};
https://riptutorial.com/ 99
class B : public A {};
class A {};
class B {};
class C : public A, public B {};
Note: this can lead to ambiguity if the same names are used in multiple inherited classs or
structs. Be careful!
Multiple inheritance may be helpful in certain cases but, sometimes odd sort of problem
encounters while using multiple inheritance.
For example: Two base classes have functions with same name which is not overridden in derived
class and if you write code to access that function using object of derived class, compiler shows
error because, it cannot determine which function to call. Here is a code for this type of ambiguity
in multiple inheritance.
class base1
{
public:
void funtion( )
{ //code for base1 function }
};
class base2
{
void function( )
{ // code for base2 function }
};
};
int main()
{
derived obj;
But, this problem can be solved using scope resolution function to specify which function to class
either base1 or base2:
int main()
{
https://riptutorial.com/ 100
obj.base1::function( ); // Function of class base1 is called.
obj.base2::function( ); // Function of class base2 is called.
}
To access member variables and member functions of an object of a class, the . operator is used:
struct SomeStruct {
int a;
int b;
void foo() {}
};
SomeStruct var;
// Accessing member variable a in var.
std::cout << var.a << std::endl;
// Assigning member variable b in var.
var.b = 1;
// Calling a member function.
var.foo();
When accessing the members of a class via a pointer, the -> operator is commonly used.
Alternatively, the instance can be dereferenced and the . operator used, although this is less
common:
struct SomeStruct {
int a;
int b;
void foo() {}
};
SomeStruct var;
SomeStruct *p = &var;
// Accessing member variable a in var via pointer.
std::cout << p->a << std::endl;
std::cout << (*p).a << std::endl;
// Assigning member variable b in var via pointer.
p->b = 1;
(*p).b = 1;
// Calling a member function via a pointer.
p->foo();
(*p).foo();
When accessing static class members, the :: operator is used, but on the name of the class
instead of an instance of it. Alternatively, the static member can be accessed from an instance or a
pointer to an instance using the . or -> operator, respectively, with the same syntax as accessing
non-static members.
struct SomeStruct {
int a;
int b;
void foo() {}
static int c;
https://riptutorial.com/ 101
static void bar() {}
};
int SomeStruct::c;
SomeStruct var;
SomeStruct* p = &var;
// Assigning static member variable c in struct SomeStruct.
SomeStruct::c = 5;
// Accessing static member variable c in struct SomeStruct, through var and p.
var.a = var.c;
var.b = p->c;
// Calling a static member function.
SomeStruct::bar();
var.bar();
p->bar();
Background
The -> operator is needed because the member access operator . has precedence over the
dereferencing operator *.
One would expect that *p.a would dereference p (resulting in a reference to the object p is pointing
to) and then accessing its member a. But in fact, it tries to access the member a of p and then
dereference it. I.e. *p.a is equivalent to *(p.a). In the example above, this would result in a
compiler error because of two facts: First, p is a pointer and does not have a member a. Second, a
is an integer and, thus, can't be dereferenced.
The uncommonly used solution to this problem would be to explicitly control the precedence:
(*p).a
Instead, the -> operator is almost always used. It is a short-hand for first dereferencing the pointer
and then accessing it. I.e. (*p).a is exactly the same as p->a.
The :: operator is the scope operator, used in the same manner as accessing a member of a
namespace. This is because a static class member is considered to be in that class' scope, but
isn't considered a member of instances of that class. The use of normal . and -> is also allowed
for static members, despite them not being instance members, for historical reasons; this is of use
for writing generic code in templates, as the caller doesn't need to be concerned with whether a
given member function is static or non-static.
Private inheritance is useful when it is required to restrict the public interface of the class:
class A {
public:
int move();
int turn();
};
class B : private A {
public:
https://riptutorial.com/ 102
using A::turn;
};
B b;
b.move(); // compile error
b.turn(); // OK
This approach efficiently prevents an access to the A public methods by casting to the A pointer or
reference:
B b;
A& a = static_cast<A&>(b); // compile error
In the case of public inheritance such casting will provide access to all the A public methods
despite on alternative ways to prevent this in derived B, like hiding:
class B : public A {
private:
int move();
};
or private using:
class B : public A {
private:
using A::move;
};
B b;
A& a = static_cast<A&>(b); // OK for public inheritance
a.move(); // OK
C++11
Deriving a class may be forbidden with final specifier. Let's declare a final class:
class A final {
};
https://riptutorial.com/ 103
class A {
};
// OK.
class B final : public A {
};
Friendship
The friend keyword is used to give other classes and functions access to private and protected
members of the class, even through they are defined outside the class`s scope.
class Animal{
private:
double weight;
double height;
public:
friend void printWeight(Animal animal);
friend class AnimalPrinter;
// A common use for a friend function is to overload the operator<< for streaming.
friend std::ostream& operator<<(std::ostream& os, Animal animal);
};
class AnimalPrinter
{
public:
void print(const Animal& animal)
{
// Because of the `friend class AnimalPrinter;" declaration, we are
// allowed to access private members here.
std::cout << animal.weight << ", " << animal.height << std::endl;
}
}
int main() {
Animal animal = {10, 5};
printWeight(animal);
AnimalPrinter aPrinter;
aPrinter.print(animal);
https://riptutorial.com/ 104
10
10, 5
Animal height: 5
Nested Classes/Structures
A class or struct can also contain another class/struct definition inside itself, which is called a
"nested class"; in this situation, the containing class is referred to as the "enclosing class". The
nested class definition is considered to be a member of the enclosing class, but is otherwise
separate.
struct Outer {
struct Inner { };
};
From outside of the enclosing class, nested classes are accessed using the scope operator. From
inside the enclosing class, however, nested classes can be used without qualifiers:
struct Outer {
struct Inner { };
Inner in;
};
// ...
Outer o;
Outer::Inner i = o.in;
As with a non-nested class/struct, member functions and static variables can be defined either
within a nested class, or in the enclosing namespace. However, they cannot be defined within the
enclosing class, due to it being considered to be a different class than the nested class.
// Bad.
struct Outer {
struct Inner {
void do_something();
};
void Inner::do_something() {}
};
// Good.
struct Outer {
struct Inner {
void do_something();
};
};
void Outer::Inner::do_something() {}
As with non-nested classes, nested classes can be forward declared and defined later, provided
https://riptutorial.com/ 105
they are defined before being used directly.
class Outer {
class Inner1;
class Inner2;
Inner1 in1;
Inner2* in2p;
public:
Outer();
~Outer();
};
C++11
Prior to C++11, nested classes only had access to type names, static members, and enumerators
from the enclosing class; all other members defined in the enclosing class were off-limits.
C++11
As of C++11, nested classes, and members thereof, are treated as if they were friends of the
enclosing class, and can access all of its members, according to the usual access rules; if
members of the nested class require the ability to evaluate one or more non-static members of the
enclosing class, they must therefore be passed an instance:
class Outer {
struct Inner {
int get_sizeof_x() {
return sizeof(x); // Legal (C++11): x is unevaluated, so no instance is required.
}
int get_x() {
return x; // Illegal: Can't access non-static member without an instance.
}
int get_x(Outer& o) {
return o.x; // Legal (C++11): As a member of Outer, Inner can access private
members.
}
};
int x;
};
Conversely, the enclosing class is not treated as a friend of the nested class, and thus cannot
access its private members without explicitly being granted permission.
https://riptutorial.com/ 106
class Outer {
class Inner {
// friend class Outer;
int x;
};
Inner in;
public:
int get_x() {
return in.x; // Error: int Outer::Inner::x is private.
// Uncomment "friend" line above to fix.
}
};
Friends of a nested class are not automatically considered friends of the enclosing class; if they
need to be friends of the enclosing class as well, this must be declared separately. Conversely, as
the enclosing class is not automatically considered a friend of the nested class, neither will friends
of the enclosing class be considered friends of the nested class.
class Outer {
friend void barge_out(Outer& out, Inner& in);
class Inner {
friend void barge_in(Outer& out, Inner& in);
int i;
};
int o;
};
As with all other class members, nested classes can only be named from outside the class if they
have public access. However, you are allowed to access them regardless of access modifier, as
long as you don't explicitly name them.
class Outer {
struct Inner {
void func() { std::cout << "I have no private taboo.\n"; }
};
public:
static Inner make_Inner() { return Inner(); }
};
https://riptutorial.com/ 107
// ...
You can also create a type alias for a nested class. If a type alias is contained in the enclosing
class, the nested type and the type alias can have different access modifiers. If the type alias is
outside the enclosing class, it requires that either the nested class, or a typedef thereof, be public.
class Outer {
class Inner_ {};
public:
typedef Inner_ Inner;
};
// ...
As with other classes, nested classes can both derive from or be derived from by other classes.
struct Outer {
struct Inner : Base {};
};
This can be useful in situations where the enclosing class is derived from by another class, by
allowing the programmer to update the nested class as necessary. This can be combined with a
typedef to provide a consistent name for each enclosing class' nested class:
class BaseOuter {
struct BaseInner_ {
virtual void do_something() {}
virtual void do_something_else();
} b_in;
public:
typedef BaseInner_ Inner;
https://riptutorial.com/ 108
void BaseOuter::BaseInner_::do_something_else() {}
// ---
public:
typedef DerivedInner_ Inner;
void DerivedOuter::DerivedInner_::do_something_else() {}
// ...
// Calls BaseOuter::BaseInner_::do_something();
BaseOuter* b = new BaseOuter;
BaseOuter::Inner& bin = b->getInner();
bin.do_something();
b->getInner().do_something();
// Calls DerivedOuter::DerivedInner_::do_something();
BaseOuter* d = new DerivedOuter;
BaseOuter::Inner& din = d->getInner();
din.do_something();
d->getInner().do_something();
In the above case, both BaseOuter and DerivedOuter supply the member type Inner, as BaseInner_
and DerivedInner_, respectively. This allows nested types to be derived without breaking the
enclosing class' interface, and allows the nested type to be used polymorphically.
A class or struct can also define member type aliases, which are type aliases contained within,
and treated as members of, the class itself.
struct IHaveATypedef {
typedef int MyTypedef;
};
struct IHaveATemplateTypedef {
template<typename T>
using MyTemplateTypedef = std::vector<T>;
};
Like static members, these typedefs are accessed using the scope operator, ::.
IHaveATypedef::MyTypedef i = 5; // i is an int.
https://riptutorial.com/ 109
IHaveATemplateTypedef::MyTemplateTypedef<int> v; // v is a std::vector<int>.
As with normal type aliases, each member type alias is allowed to refer to any type defined or
aliased before, but not after, its definition. Likewise, a typedef outside the class definition can refer
to any accessible typedefs within the class definition, provided it comes after the class definition.
template<typename T>
struct Helper {
T get() const { return static_cast<T>(42); }
};
struct IHaveTypedefs {
// typedef MyTypedef NonLinearTypedef; // Error if uncommented.
typedef int MyTypedef;
typedef Helper<MyTypedef> MyTypedefHelper;
};
Member type aliases can be declared with any access level, and will respect the appropriate
access modifier.
class TypedefAccessLevels {
typedef int PrvInt;
protected:
typedef int ProInt;
public:
typedef int PubInt;
};
This can be used to provide a level of abstraction, allowing a class' designer to change its internal
workings without breaking code that relies on it.
class Something {
friend class SomeComplexType;
short s;
// ...
https://riptutorial.com/ 110
public:
typedef SomeComplexType MyHelper;
// ...
};
// ...
Something s;
Something::MyHelper hlp = s.get_helper();
In this situation, if the helper class is changed from SomeComplexType to some other type, only the
typedef and the friend declaration would need to be modified; as long as the helper class provides
the same functionality, any code that uses it as Something::MyHelper instead of specifying it by
name will usually still work without any modifications. In this manner, we minimise the amount of
code that needs to be modified when the underlying implementation is changed, such that the type
name only needs to be changed in one location.
class SomethingElse {
AnotherComplexType<bool, int, SomeThirdClass> helper;
public:
typedef decltype(helper) MyHelper;
private:
InternalVariable<MyHelper> ivh;
// ...
public:
MyHelper& get_helper() const { return helper; }
// ...
};
As with everything, however, this can be taken too far. If the typename is only used once or twice
internally and zero times externally, for example, there's no need to provide an alias for it. If it's
used hundreds or thousands of times throughout a project, or if it has a long enough name, then it
can be useful to provide it as a typedef instead of always using it in absolute terms. One must
balance forwards compatibility and convenience with the amount of unnecessary noise created.
This can also be used with template classes, to provide access to the template parameters from
outside the class.
template<typename T>
https://riptutorial.com/ 111
class SomeClass {
// ...
public:
typedef T MyParam;
MyParam getParam() { return static_cast<T>(42); }
};
template<typename T>
typename T::MyParam some_func(T& t) {
return t.getParam();
}
SomeClass<int> si;
int i = some_func(si);
This is commonly used with containers, which will usually provide their element type, and other
helper types, as member type aliases. Most of the containers in the C++ standard library, for
example, provide the following 12 helper types, along with any other special types they might
need.
template<typename T>
class SomeContainer {
// ...
public:
// Let's provide the same helper types as most standard containers.
typedef T value_type;
typedef std::allocator<value_type> allocator_type;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef MyIterator<value_type> iterator;
typedef MyConstIterator<value_type> const_iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
};
Prior to C++11, it was also commonly used to provide a "template typedef" of sorts, as the feature
wasn't yet available; these have become a bit less common with the introduction of alias
templates, but are still useful in some situations (and are combined with alias templates in other
situations, which can be very useful for obtaining individual components of a complex type such as
a function pointer). They commonly use the name type for their type alias.
template<typename T>
struct TemplateTypedef {
typedef T type;
}
TemplateTypedef<int>::type i; // i is an int.
This was often used with types with multiple template parameters, to provide an alias that defines
https://riptutorial.com/ 112
one or more of the parameters.
template<typename T>
struct MonoDisplayLine {
typedef Array<T, 80, 1> type;
};
A class is also allowed to have static members, which can be either variables or functions. These
are considered to be in the class' scope, but aren't treated as normal members; they have static
storage duration (they exist from the start of the program to the end), aren't tied to a particular
instance of the class, and only one copy exists for the entire class.
class Example {
static int num_instances; // Static data member (static member variable).
int i; // Non-static member variable.
public:
static std::string static_str; // Static data member (static member variable).
static int static_func(); // Static member function.
int Example::num_instances;
std::string Example::static_str = "Hello.";
// ...
https://riptutorial.com/ 113
// (&two.num_instances == &three.num_instances)
Static member variables are not considered to be defined inside the class, only declared, and thus
have their definition outside the class definition; the programmer is allowed, but not required, to
initialise static variables in their definition. When defining the member variables, the keyword
static is omitted.
class Example {
static int num_instances; // Declaration.
public:
static std::string static_str; // Declaration.
// ...
};
Due to this, static variables can be incomplete types (apart from void), as long as they're later
defined as a complete type.
struct ForwardDeclared;
class ExIncomplete {
static ForwardDeclared fd;
static ExIncomplete i_contain_myself;
static int an_array[];
};
ForwardDeclared ExIncomplete::fd;
ExIncomplete ExIncomplete::i_contain_myself;
int ExIncomplete::an_array[5];
Static member functions can be defined inside or outside the class definition, as with normal
member functions. As with static member variables, the keyword static is omitted when defining
static member functions outside the class definition.
public:
static int static_func() { return num_instances; }
// ...
// Or...
https://riptutorial.com/ 114
int Example::static_func() { return num_instances; }
void Example::set_str(const std::string& str) { static_str = str; }
If a static member variable is declared const but not volatile, and is of an integral or enumeration
type, it can be initialised at declaration, inside the class definition.
enum E { VAL = 5 };
struct ExConst {
const static int ci = 5; // Good.
static const E ce = VAL; // Good.
const static double cd = 5; // Error.
static const volatile int cvi = 5; // Error.
C++11
As of C++11, static member variables of LiteralType types (types that can be constructed at
compile time, according to constexpr rules) can also be declared as constexpr; if so, they must be
initialised within the class definition.
struct ExConstexpr {
constexpr static int ci = 5; // Good.
static constexpr double cd = 5; // Good.
constexpr static int carr[] = { 1, 1, 2 }; // Good.
static constexpr ConstexprConstructibleClass c{}; // Good.
constexpr static int bad_ci; // Error.
};
If a const or constexpr static member variable is odr-used (informally, if it has its address taken or
is assigned to a reference), then it must still have a separate definition, outside the class definition.
This definition is not allowed to contain an initialiser.
struct ExODR {
static const int odr_used = 5;
};
const int* odr_user = & ExODR::odr_used; // Error; uncomment above line to resolve.
As static members aren't tied to a given instance, they can be accessed using the scope operator,
::.
https://riptutorial.com/ 115
std::string str = Example::static_str;
They can also be accessed as if they were normal, non-static members. This is of historical
significance, but is used less commonly than the scope operator to prevent confusion over
whether a member is static or non-static.
Example ex;
std::string rts = ex.static_str;
Class members are able to access static members without qualifying their scope, as with non-
static class members.
class ExTwo {
static int num_instances;
int my_num;
public:
ExTwo() : my_num(num_instances++) {}
int ExTwo::num_instances;
They cannot be mutable, nor would they need to be; as they aren't tied to any given instance,
whether an instance is or isn't const doesn't affect static members.
struct ExDontNeedMutable {
int immuta;
mutable int muta;
static int i;
// ...
class ExAccess {
static int prv_int;
protected:
static int pro_int;
https://riptutorial.com/ 116
public:
static int pub_int;
};
int ExAccess::prv_int;
int ExAccess::pro_int;
int ExAccess::pub_int;
// ...
As they aren't tied to a given instance, static member functions have no this pointer; due to this,
they can't access non-static member variables unless passed an instance.
class ExInstanceRequired {
int i;
public:
ExInstanceRequired() : i(0) {}
Due to not having a this pointer, their addresses can't be stored in pointers-to-member-functions,
and are instead stored in normal pointers-to-functions.
struct ExPointer {
void nsfunc() {}
static void sfunc() {}
};
Due to not having a this pointer, they also cannot be const or volatile, nor can they have ref-
qualifiers. They also cannot be virtual.
struct ExCVQualifiersAndVirtual {
static void func() {} // Good.
static void cfunc() const {} // Error.
static void vfunc() volatile {} // Error.
static void cvfunc() const volatile {} // Error.
static void rfunc() & {} // Error.
static void rvfunc() && {} // Error.
https://riptutorial.com/ 117
};
As they aren't tied to a given instance, static member variables are effectively treated as special
global variables; they're created when the program starts, and destroyed when it exits, regardless
of whether any instances of the class actually exist. Only a single copy of each static member
variable exists (unless the variable is declared thread_local (C++11 or later), in which case there's
one copy per thread).
Static member variables have the same linkage as the class, whether the class has external or
internal linkage. Local classes and unnamed classes aren't allowed to have static members.
A class can have non-static member functions, which operate on individual instances of the class.
class CL {
public:
void member_function() {}
};
CL instance;
instance.member_function();
They can be defined either inside or outside the class definition; if defined outside, they are
specified as being in the class' scope.
struct ST {
void defined_inside() {}
void defined_outside();
};
void ST::defined_outside() {}
They can be CV-qualified and/or ref-qualified, affecting how they see the instance they're called
upon; the function will see the instance as having the specified cv-qualifier(s), if any. Which
version is called will be based on the instance's cv-qualifiers. If there is no version with the same
cv-qualifiers as the instance, then a more-cv-qualified version will be called if available.
struct CVQualifiers {
void func() {} // 1: Instance is non-cv-qualified.
void func() const {} // 2: Instance is const.
CVQualifiers non_cv_instance;
const CVQualifiers c_instance;
https://riptutorial.com/ 118
non_cv_instance.cv_only(); // Calls const volatile version.
c_instance.cv_only(); // Calls const volatile version.
C++11
Member function ref-qualifiers indicate whether or not the function is intended to be called on
rvalue instances, and use the same syntax as function cv-qualifiers.
struct RefQualifiers {
void func() & {} // 1: Called on normal instances.
void func() && {} // 2: Called on rvalue (temporary) instances.
};
RefQualifiers rf;
rf.func(); // Calls #1.
RefQualifiers{}.func(); // Calls #2.
struct BothCVAndRef {
void func() const& {} // Called on normal instances. Sees instance as const.
void func() && {} // Called on temporary instances.
};
They can also be virtual; this is fundamental to polymorphism, and allows a child class(es) to
provide the same interface as the parent class, while supplying their own functionality.
struct Base {
virtual void func() {}
};
struct Derived {
virtual void func() {}
};
Unnamed struct/class
void foo()
{
struct /* No name */ {
float x;
float y;
} point;
point.x = 42;
https://riptutorial.com/ 119
}
or
struct Circle
{
struct /* No name */ {
float x;
float y;
} center; // but a member name
float radius;
};
and later
Circle circle;
circle.center.x = 42.f;
struct InvalidCircle
{
struct /* No name */ {
float centerX;
float centerY;
}; // No member either.
float radius;
};
C++11
decltype(circle.point) otherPoint;
void print_square_coordinates()
{
const struct {float x; float y;} points[] = {
{-1, -1}, {-1, 1}, {1, -1}, {1, 1}
};
https://riptutorial.com/ 120
auto it = std::find(points, points + 4, topRightCorner);
std::cout << "top right corner is the "
<< 1 + std::distance(points, it) << "th\n";
}
https://riptutorial.com/ 121
Chapter 23: Client server examples
Examples
Hello TCP Server
Let me start by saying you should first visit Beej's Guide to Network Programming and give it a
quick read, which explains most of this stuff a bit more verbosely. We'll be creating a simple TCP
server here which will say "Hello World" to all incoming connections and then close them. Another
thing to note is, the server will be communicating to clients iteratively, which means one client at a
time. Make sure to check out relevant man pages as they might contain valuable information about
each function call and socket structures.
We'll run the server with a port, so we'll take an argument for port number as well. Let's get started
with code -
addrinfo hints, *res, *p; // we need 2 pointers, res to hold and p to iterate over
memset(&hints, 0, sizeof(hints));
// man getaddrinfo
int gAddRes = getaddrinfo(NULL, portNum, &hints, &res);
if (gAddRes != 0) {
std::cerr << gai_strerror(gAddRes) << "\n";
https://riptutorial.com/ 122
return -2;
}
// if no addresses found :(
if (!numOfAddr) {
std::cerr << "Found no host address to use\n";
return -3;
}
p = res;
https://riptutorial.com/ 123
// let's create a new socket, socketFD is returned as descriptor
// man socket for more information
// these calls usually return -1 as result of some error
int sockFD = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (sockFD == -1) {
std::cerr << "Error while creating socket\n";
freeaddrinfo(res);
return -4;
}
// if some error occurs, make sure to close socket and free resources
close(sockFD);
freeaddrinfo(res);
return -5;
}
// if some error occurs, make sure to close socket and free resources
close(sockFD);
freeaddrinfo(res);
return -6;
}
// send call sends the data you specify as second param and it's length as 3rd param,
also returns how many bytes were actually sent
auto bytes_sent = send(newFD, response.data(), response.length(), 0);
close(newFD);
https://riptutorial.com/ 124
}
close(sockFD);
freeaddrinfo(res);
return 0;
}
Detecting addresses
(1) IPv4 : 0.0.0.0
(2) IPv6 : ::
Enter the number of host address to bind with: 1
This program is complimentary to Hello TCP Server program, you can run either of them to check
the validity of each other. The program flow is quite common with Hello TCP server, so make sure
to take a look at that too.
#include <cstring>
#include <iostream>
#include <string>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
https://riptutorial.com/ 125
if (p == NULL) {
std::cerr << "No addresses found\n";
return -3;
}
return 0;
}
https://riptutorial.com/ 126
Chapter 24: Common compile/linker errors
(GCC)
Examples
error: '***' was not declared in this scope
Variables
Not compiling:
#include <iostream>
std::cout << i << std::endl; // i is not in the scope of the main function
return 0;
}
Fix:
#include <iostream>
return 0;
}
Functions
Most of the time this error occurs if the needed header is not included (e.g. using
std::cout without #include <iostream>)
Not compiling:
#include <iostream>
https://riptutorial.com/ 127
int main(int argc, char *argv[])
{
doCompile();
return 0;
}
void doCompile()
{
std::cout << "No!" << std::endl;
}
Fix:
#include <iostream>
return 0;
}
void doCompile()
{
std::cout << "No!" << std::endl;
}
Or:
#include <iostream>
return 0;
}
Note: The compiler interprets the code from top to bottom (simplification). Everything must be at
least declared (or defined) before usage.
This linker error happens, if the linker can't find a used symbol. Most of the time, this happens if a
used library is not linked against.
qmake:
https://riptutorial.com/ 128
LIBS += nameOfLib
cmake:
TARGET_LINK_LIBRARIES(target nameOfLib)
g++ call:
One might also forget to compile and link all used .cpp files (functionsModule.cpp defines the
needed function):
The compiler can't find a file (a source file uses #include "someFile.hpp").
qmake:
INCLUDEPATH += dir/Of/File
cmake:
include_directories(dir/Of/File)
g++ call:
https://riptutorial.com/ 129
Chapter 25: Compiling and Building
Introduction
Programs written in C++ need to be compiled before they can be run. There is a large variety of
compilers available depending on your operating system.
Remarks
Most operating systems ship without a compiler, and they have to be installed later. Some
common compilers choices are:
Please consult the appropriate compiler manual, on how to compile a C++ program.
Another option to use a specific compiler with its own specific build system, it is possible to let
generic build systems configure the project for a specific compiler or for the default installed one.
Examples
Compiling with GCC
Assuming a single source file named main.cpp, the command to compile and link an non-optimized
executable is as follows (Compiling without optimization is useful for initial development and
debugging, although -Og is officially recommended for newer GCC versions).
To produce an optimized executable for use in production, use one of the -O options (see: -O1, -O2,
-O3, -Os, -Ofast):
If the -O option is omitted, -O0, which means no optimizations, is used as default (specifying -O
without a number resolves to -O1).
Alternatively, use optimization flags from the O groups (or more experimental optimizations)
directly. The following example builds with -O2 optimization, plus one flag from the -O3 optimization
level:
https://riptutorial.com/ 130
To produce a platform-specific optimized executable (for use in production on the machine with
the same architecture), use:
Either of the above will produce a binary file that can be run with .\app.exe on Windows and ./app
on Linux, Mac OS, etc.
The -o flag can also be skipped. In this case, GCC will create default output executable a.exe on
Windows and a.out on Unix-like systems. To compile a file without linking it, use the -c option:
This produces an object file named file.o which can later be linked with other files to produce a
binary:
More about optimization options can be found at gcc.gnu.org. Of particular note are -Og
(optimization with an emphasis on debugging experience -- recommended for the standard edit-
compile-debug cycle) and -Ofast (all optimizations, including ones disregarding strict standards
compliance).
The -Wall flag enables warnings for many common errors and should always be used. To improve
code quality it is often encouraged also to use -Wextra and other warning flags which are not
automatically enabled by -Wall and -Wextra.
If the code expects a specific C++ standard, specify which standard to use by including the -std=
flag. Supported values correspond to the year of finalization for each version of the ISO C++
standard. As of GCC 6.1.0, valid values for the std= flag are c++98/c++03, c++11, c++14, and c++17/
c++1z. Values separated by a forward slash are equivalent.
GCC includes some compiler-specific extensions that are disabled when they conflict with a
standard specified by the -std= flag. To compile with all extensions enabled, the value gnu++XX may
be used, where XX is any of the years used by the c++ values listed above.
The default standard will be used if none is specified. For versions of GCC prior to 6.1.0, the
default is -std=gnu++03; in GCC 6.1.0 and greater, the default is -std=gnu++14.
Note that due to bugs in GCC, the -pthread flag must be present at compilation and linking for
GCC to support the C++ standard threading functionality introduced with C++11, such as
std::thread and std::wait_for. Omitting it when using threading functions may result in no
warnings but invalid results on some platforms.
https://riptutorial.com/ 131
Linking with libraries:
Use the -l option to pass the library name:
If the library is not in the standard library path, add the path with -L option:
If one library depends on another, put the dependent library before the independent library:
Or let the linker determine the ordering itself via --start-group and --end-group (note: this has
significant performance cost):
For programmers coming from GCC or Clang to Visual Studio, or programmers more comfortable
with the command line in general, you can use the Visual C++ compiler from the command line as
well as the IDE.
If you desire to compile your code from the command line in Visual Studio, you first need to set up
the command line environment. This can be done either by opening the Visual Studio Command
Prompt/Developer Command Prompt/x86 Native Tools Command Prompt/x64 Native Tools Command Prompt or
similar (as provided by your version of Visual Studio), or at the command prompt, by navigating to
the VC subdirectory of the compiler's install directory (typically \Program Files (x86)\Microsoft
Visual Studio x\VC, where x is the version number (such as 10.0 for 2010, or 14.0 for 2015) and
running the VCVARSALL batch file with a command-line parameter specified here.
Note that unlike GCC, Visual Studio doesn't provide a front-end for the linker (link.exe) via the
compiler (cl.exe), but instead provides the linker as a separate program, which the compiler calls
as it exits. cl.exe and link.exe can be used separately with different files and options, or cl can be
told to pass files and options to link if both tasks are done together. Any linking options specified
to cl will be translated into options for link, and any files not processed by cl will be passed
directly to link. As this is mainly a simple guide to compiling with the Visual Studio command line,
arguments for link will not be described at this time; if you need a list, see here.
https://riptutorial.com/ 132
Note that arguments to cl are case-sensitive, while arguments to link are not.
[Be advised that some of the following examples use the Windows shell "current directory"
variable, %cd%, when specifying absolute path names. For anyone unfamiliar with this variable, it
expands to the current working directory. From the command line, it will be the directory you were
in when you ran cl, and is specified in the command prompt by default (if your command prompt is
C:\src>, for example, then %cd% is C:\src\).]
Assuming a single source file named main.cpp in the current folder, the command to compile and
link an unoptimised executable (useful for initial development and debugging) is (use either of the
following):
cl main.cpp
// Generates object file "main.obj".
// Performs linking with "main.obj".
// Generates executable "main.exe".
cl /Od main.cpp
// Same as above.
// "/Od" is the "Optimisation: disabled" option, and is the default when no /O is specified.
Assuming an additional source file "niam.cpp" in the same directory, use the following:
cl main.cpp niam.cpp
// Generates object files "main.obj" and "niam.obj".
// Performs linking with "main.obj" and "niam.obj".
// Generates executable "main.exe".
cl main.cpp src\*.cpp
// Generates object file "main.obj", plus one object file for each ".cpp" file in folder
// "%cd%\src".
// Performs linking with "main.obj", and every additional object file generated.
// All object files will be in the current folder.
// Generates executable "main.exe".
cl /o name main.cpp
// Generates executable named "name.exe".
cl /o folder\ main.cpp
// Generates executable named "main.exe", in folder "%cd%\folder".
cl /o folder\name main.cpp
// Generates executable named "name.exe", in folder "%cd%\folder".
cl /Fename main.cpp
// Same as "/o name".
cl /Fefolder\ main.cpp
// Same as "/o folder\".
https://riptutorial.com/ 133
cl /Fefolder\name main.cpp
// Same as "/o folder\name".
Both /o and /Fe pass their parameter (let's call it o-param) to link as /OUT:o-param, appending the
appropriate extension (generally .exe or .dll) to "name" o-params as necessary. While both /o and
/Fe are to my knowledge identical in functionality, the latter is preferred for Visual Studio. /o is
marked as deprecated, and appears to mainly be provided for programmers more familiar with
GCC or Clang.
Note that while the space between /o and the specified folder and/or name is optional, there
cannot be a space between /Fe and the specified folder and/or name.
cl /O1 main.cpp
// Optimise for executable size. Produces small programs, at the possible expense of slower
// execution.
cl /O2 main.cpp
// Optimise for execution speed. Produces fast programs, at the possible expense of larger
// file size.
Finally, to produce a platform-specific optimized executable (for use in production on the machine
with the specified architecture), choose the appropriate command prompt or VCVARSALL parameter
for the target platform. link should detect the desired platform from the object files; if not, use the
/MACHINE option to explicitly specify the target platform.
// If compiling for x64, and LINK doesn't automatically detect target platform:
cl main.cpp /link /machine:X64
Any of the above will produce an executable with the name specified by /o or /Fe, or if neither is
provided, with a name identical to the first source or object file specified to the compiler.
https://riptutorial.com/ 134
cl /o yo zp.obj pz.cpp
// Generates "yo.exe".
cl /c main.cpp
// Generates object file "main.obj".
This tells cl to exit without calling link, and produces an object file, which can later be linked with
other files to produce a binary.
cl main.obj niam.cpp
// Generates object file "niam.obj".
// Performs linking with "main.obj" and "niam.obj".
// Generates executable "main.exe".
There are other valuable command line parameters as well, which it would be very useful for users
to know:
cl /EHsc main.cpp
// "/EHsc" specifies that only standard C++ ("synchronous") exceptions will be caught,
// and `extern "C"` functions will not throw exceptions.
// This is recommended when writing portable, platform-independent code.
cl /clr main.cpp
// "/clr" specifies that the code should be compiled to use the common language runtime,
// the .NET Framework's virtual machine.
// Enables the use of Microsoft's C++/CLI language in addition to standard ("native") C++,
// and creates an executable that requires .NET to run.
cl /Za main.cpp
// "/Za" specifies that Microsoft extensions should be disabled, and code should be
// compiled strictly according to ISO C++ specifications.
// This is recommended for guaranteeing portability.
cl /Zi main.cpp
// "/Zi" generates a program database (PDB) file for use when debugging a program, without
// affecting optimisation specifications, and passes the option "/DEBUG" to LINK.
cl /LD dll.cpp
// "/LD" tells CL to configure LINK to generate a DLL instead of an executable.
// LINK will output a DLL, in addition to an LIB and EXP file for use when linking.
// To use the DLL in other programs, pass its associated LIB to CL or LINK when compiling
those
// programs.
https://riptutorial.com/ 135
For anyone more familiar with *nix systems and/or GCC/Clang, cl, link, and other Visual Studio
command line tools can accept parameters specified with a hyphen (such as -c) instead of a slash
(such as /c). Additionally, Windows recognises either a slash or a backslash as a valid path
separator, so *nix-style paths can be used as well. This makes it easy to convert simple compiler
command lines from g++ or clang++ to cl, or vice versa, with minimal changes.
Of course, when porting command lines that use more complex g++ or clang++ options, you need to
look up equivalent commands in the applicable compiler documentations and/or on resource sites,
but this makes it easier to get things started with minimal time spent learning about new compilers.
In case you need specific language features for your code, a specific release of MSVC was
required. From Visual C++ 2015 Update 3 on it is possible to choose the version of the standard to
compile with via the /std flag. Possible values are /std:c++14 and /std:c++latest (/std:c++17 will
follow soon).
Note: In older versions of this compiler, specific feature flags were available however this was
mostly used for previews of new features.
4. Click Templates -> Visual C++ -> Win32 Console Application and then name the project
MyFirstProgram.
https://riptutorial.com/ 136
5. Click Ok
6. Click Next in the following window.
https://riptutorial.com/ 137
7. Check the Empty project box and then click Finish:
https://riptutorial.com/ 138
8. Right click on folder Source File then -> Add --> New Item :
https://riptutorial.com/ 139
9. Select C++ File and name the file main.cpp, then click Add:
https://riptutorial.com/ 140
10: Copy and paste the following code in the new file main.cpp:
#include <iostream>
int main()
{
std::cout << "Hello World!\n";
return 0;
}
https://riptutorial.com/ 141
11. Click Debug -> Start Without Debugging (or press ctrl + F5) :
https://riptutorial.com/ 142
Compiling with Clang
As the Clang front-end is designed for being compatible with GCC, most programs that can be
compiled via GCC will compile when you swap g++ by clang++ in the build scripts. If no -std=version
is given, gnu11 will be used.
Windows users who are used to MSVC can swap cl.exe with clang-cl.exe. By default, clang tries
to be compatible with the highest version of MSVC that has been installed.
In the case of compiling with visual studio, clang-cl can be used by changing the Platform toolset
in the project properties.
In both cases, clang is only compatible via its front-end, though it also tries to generate binary
compatible object files. Users of clang-cl should note that the compatibility with MSVC is not
complete yet.
To use clang or clang-cl, one could use the default installation on certain Linux distributions or
those bundled with IDEs (like XCode on Mac). For other versions of this compiler or on platforms
which don't have this installed, this can be download from the official download page.
If you're using CMake to build your code you can usually switch the compiler by setting the CC and
CXX environment variables like this:
mkdir build
cd build
CC=clang CXX=clang++ cmake ..
cmake --build .
Online Compilers
https://riptutorial.com/ 143
Various websites provide online access to C++ compilers. Online compiler's feature set vary
significantly from site to site, but usually they allow to do the following:
Online compiler website behavior is usually quite restrictive as they allow anyone to run compilers
and execute arbitrary code on their server side, whereas ordinarily remote arbitrary code
execution is considered as vulnerability.
• Run a small code snippet from a machine which lacks C++ compiler (smartphones, tablets,
etc.).
• Ensure that code compiles successfully with different compilers and runs the same way
regardless the compiler it was compiled with.
• Learn or teach basics of C++.
• Learn modern C++ features (C++14 and C++17 in near future) when up-to-date C++
compiler is not available on local machine.
• Spot a bug in your compiler by comparison with a large set of other compilers. Check if a
compiler bug was fixed in future versions, which are unavailable on your machine.
• Solve online judge problems.
• Develop full-featured (even small) applications using C++. Usually online compilers do not
allow to link with third-party libraries or download build artifacts.
• Perform intensive computations. Sever-side computing resources are limited, so any user-
provided program will be killed after a few seconds of execution. The permitted execution
time is usually enough for testing and learning.
• Attack compiler server itself or any third-party hosts on the net.
Examples:
Disclaimer: documentation author(s) are not affiliated with any resources listed below.
Websites are listed alphabetically.
• http://codepad.org/ Online compiler with code sharing. Editing code after compiling with a
source code warning or error does not work so well.
• http://coliru.stacked-crooked.com/ Online compiler for which you specify the command line.
Provides both GCC and Clang compilers for use.
• http://cpp.sh/ - Online compiler with C++14 support. Does not allow you to edit compiler
command line, but some options are available via GUI controls.
• https://gcc.godbolt.org/ - Provides a wide list of compiler versions, architectures, and
disassembly output. Very useful when you need to inspect what your code compiles into by
different compilers. GCC, Clang, MSVC (CL), Intel compiler (icc), ELLCC, and Zapcc are
present, with one or more of these compilers available for the ARM, ARMv8 (as ARM64),
https://riptutorial.com/ 144
Atmel AVR, MIPS, MIPS64, MSP430, PowerPC, x86, and x64 architecutres. Compiler
command line arguments may be edited.
• https://ideone.com/ - Widely used on the Net to illustrate code snippet behavior. Provides
both GCC and Clang for use, but doesn't allow you to edit the compiler command line.
• http://melpon.org/wandbox - Supports numerous Clang and GNU/GCC compiler versions.
• http://onlinegdb.com/ - An extremely minimalistic IDE that includes an editor, a compiler
(gcc), and a debugger (gdb).
• http://rextester.com/ - Provides Clang, GCC, and Visual Studio compilers for both C and C++
(along with compilers for other languages), with the Boost library available for use.
• http://tutorialspoint.com/compile_cpp11_online.php - Full-featured UNIX shell with GCC, and
a user-friendly project explorer.
• http://webcompiler.cloudapp.net/ - Online Visual Studio 2015 compiler, provided by Microsoft
as part of RiSE4fun.
When you develop a C++ program, the next step is to compile the program before running it. The
compilation is the process which converts the program written in human readable language like C,
C++ etc into a machine code, directly understood by the Central Processing Unit. For example, if
you have a C++ source code file named prog.cpp and you execute the compile command,
There are 4 main stages involved in creating an executable file from the source file.
1. The C++ the preprocessor takes a C++ source code file and deals with the
headers(#include), macros(#define) and other preprocessor directives.
2. The expanded C++ source code file produced by the C++ preprocessor is compiled into the
assembly language for the platform.
3. The assembler code generated by the compiler is assembled into the object code for the
platform.
Preprocessing
The preprocessor handles the preprocessor directives, like #include and #define. It is agnostic of
the syntax of C++, which is why it must be used with care.
It works on one C++ source file at a time by replacing #include directives with the content of the
respective files (which is usually just declarations), doing replacement of macros (#define), and
selecting different portions of text depending of #if, #ifdef and #ifndef directives.
https://riptutorial.com/ 145
replacing tokens with other tokens (the operator ## enables merging two tokens when it make
sense).
After all this, the preprocessor produces a single output that is a stream of tokens resulting from
the transformations described above. It also adds some special markers that tell the compiler
where each line came from so that it can use those to produce sensible error messages.
Some errors can be produced at this stage with clever use of the #if and #error directives.
By using below compiler flag, we can stop the process at preprocessing stage.
g++ -E prog.cpp
Compilation
The compilation step is performed on each output of the preprocessor. The compiler parses the
pure C++ source code (now without any preprocessor directives) and converts it into assembly
code. Then invokes underlying back-end(assembler in toolchain) that assembles that code into
machine code producing actual binary file in some format(ELF, COFF, a.out, ...). This object file
contains the compiled code (in binary form) of the symbols defined in the input. Symbols in object
files are referred to by name.
Object files can refer to symbols that are not defined. This is the case when you use a declaration,
and don't provide a definition for it. The compiler doesn't mind this, and will happily produce the
object file as long as the source code is well-formed.
Compilers usually let you stop compilation at this point. This is very useful because with it you can
compile each source code file separately. The advantage this provides is that you don't need to
recompile everything if you only change a single file.
The produced object files can be put in special archives called static libraries, for easier reusing
later on.
It's at this stage that "regular" compiler errors, like syntax errors or failed overload resolution
errors, are reported.
In order to stop the process after the compile step, we can use the -S option:
Assembling
The assembler creates object code. On a UNIX system you may see files with a .o suffix (.OBJ on
MSDOS) to indicate object code files. In this phase the assembler converts those object files from
assembly code into machine level instructions and the file created is a relocatable object code.
Hence, the compilation phase generates the relocatable object program and this program can be
used in different places without having to compile again.
To stop the process after the assembly step, you can use the -c option:
https://riptutorial.com/ 146
g++ -Wall -ansi -c prog.cpp
Linking
The linker is what produces the final compilation output from the object files the assembler
produced. This output can be either a shared (or dynamic) library (and while the name is similar,
they don't have much in common with static libraries mentioned earlier) or an executable.
It links all the object files by replacing the references to undefined symbols with the correct
addresses. Each of these symbols can be defined in other object files or in libraries. If they are
defined in libraries other than the standard library, you need to tell the linker about them.
At this stage the most common errors are missing definitions or duplicate definitions. The former
means that either the definitions don't exist (i.e. they are not written), or that the object files or
libraries where they reside were not given to the linker. The latter is obvious: the same symbol was
defined in two different object files or libraries.
1. Download and install Code::Blocks here. If you're on Windows, be careful to select a file for
which the name contains mingw, the other files don't install any compiler.
https://riptutorial.com/ 147
https://riptutorial.com/ 148
3. Select "Console application" and click "Go":
4. Click "Next", select "C++", click "Next", select a name for your project and choose a folder to
save it in, click "Next" and then click "Finish".
5. Now you can edit and compile your code. A default code that prints "Hello world!" in the
console is already there. To compile and/or run your program, press one of the three
compile/run buttons in the toolbar:
https://riptutorial.com/ 149
https://riptutorial.com/ 150
To compile without running, press , to run without compiling again, press and to
compile and then run, press .
Compiling and running the default "Hello world!" code gives the following result:
https://riptutorial.com/ 151
building
https://riptutorial.com/ 152
Chapter 26: Concurrency With OpenMP
Introduction
This topic covers the basics of concurrency in C++ using OpenMP. OpenMP is documented in
more detail in the OpenMP tag.
Remarks
OpenMP does not require any special headers or libraries as it is a built-in compiler feature.
However, if you use any OpenMP API functions such as omp_get_thread_num(), you will need to
include omp.h and its library.
OpenMP pragma statements are ignored when the OpenMP option is not enabled during
compilation. You may want to refer to the compiler option in your compiler's manual.
Examples
OpenMP: Parallel Sections
As OpenMP is a built-in compiler feature, it works on any supported compilers without including
any libraries. You may wish to include omp.h if you want to use any of the openMP API features.
Sample Code
https://riptutorial.com/ 153
}
#pragma omp section
{
std::cout << "world " << std::endl;
/** Do something **/
}
}
// This line will not be executed until all the
// sections defined above terminates
std::cout << "end" << std::endl;
Outputs
This example produces 2 possible outputs and is dependent on the operating system and
hardware. The output also illustrates a race condition problem that would occur from such an
implementation.
OUTPUT A OUTPUT B
Output
https://riptutorial.com/ 154
• begin forever hello world end
As execution order is not guaranteed, you may observe any of the above output.
This example shows how to divide a loop into equal parts and execute them in parallel.
// Continue process
// Only when all threads completed their allocated
// loop job
...
*Please take extra care to not modify the size of the vector used in parallel for loops as allocated
range indices doesn't update automatically.
This example illustrates a concept to perform reduction or gathering using std::vector and
OpenMP.
Supposed we have a scenario where we want multiple threads to help us generate a bunch of
stuff, int is used here for simplicity and can be replaced with other data types.
This is particularly useful when you need to merge results from slaves to avoid segement faults or
memory access violations and do not wish to use libraries or custom sync container libraries.
// Tell the compiler to use all threads allocated for this parallel region
// to perform this loop in parts. Actual load appx = 1000000 / Thread Qty
https://riptutorial.com/ 155
// The nowait keyword tells the compiler that the slave threads don't
// have to wait for all other slaves to finish this for loop job
#pragma omp for nowait
for (size_t i = 0; i < 1000000; ++i
{
/* Do something */
....
Slave.push_back(...);
}
https://riptutorial.com/ 156
Chapter 27: Const Correctness
Syntax
• class ClassOne { public: bool non_modifying_member_function() const { /* ... */ } };
• int ClassTwo::non_modifying_member_function() const { /* ... */ }
• void ClassTwo::modifying_member_function() { /* ... */ }
• char non_param_modding_func(const ClassOne& one, const ClassTwo* two) { /* ... */ }
• float parameter_modifying_function(ClassTwo& one, ClassOne* two) { /* ... */ }
• short ClassThree::non_modding_non_param_modding_f(const ClassOne&) const { /* ... */ }
Remarks
const correctness is a very useful troubleshooting tool, as it allows the programmer to quickly
determine which functions might be inadvertently modifying code. It also prevents unintentional
errors, such as the one shown in Const Correct Function Parameters, from compiling properly and
going unnoticed.
It is much easier to design a class for const correctness, than it is to later add const correctness to
a pre-existing class. If possible, design any class that can be const correct so that it is const
correct, to save yourself and others the hassle of later modifying it.
Note that this can also be applied to volatile correctness if necessary, with the same rules as for
const correctness, but this is used much less often.
Refrences :
ISO_CPP
C++ Tutorial
Examples
The Basics
const correctness is the practice of designing code so that only code that needs to modify an
instance is able to modify an instance (i.e. has write access), and conversely, that any code that
doesn't need to modify an instance is unable to do so (i.e. only has read access). This prevents
the instance from being modified unintentionally, making code less errorprone, and documents
whether the code is intended to change the instance's state or not. It also allows instances to be
treated as const whenever they don't need to be modified, or defined as const if they don't need to
be changed after initialisation, without losing any functionality.
https://riptutorial.com/ 157
This is done by giving member functions const CV-qualifiers, and by making pointer/reference
parameters const, except in the case that they need write access.
class ConstCorrectClass {
int x;
public:
int getX() const { return x; } // Function is const: Doesn't modify instance.
void setX(int i) { x = i; } // Not const: Modifies instance.
};
// ...
Due to the nature of const correctness, this starts with the class' member functions, and works its
way outwards; if you try to call a non-const member function from a const instance, or from a non-
const instance being treated as const, the compiler will give you an error about it losing cv-
qualifiers.
In a const-correct class, all member functions which don't change logical state have this cv-
qualified as const, indicating that they don't modify the object (apart from any mutable fields, which
can freely be modified even in const instances); if a const cv-qualified function returns a reference,
that reference should also be const. This allows them to be called on both constant and non-cv-
qualified instances, as a const T* is capable of binding to either a T* or a const T*. This, in turn,
allows functions to declare their passed-by-reference parameters as const when they don't need to
be modified, without losing any functionality.
Furthermore, in a const correct class, all passed-by-reference function parameters will be const
correct, as discussed in Const Correct Function Parameters, so that they can only be modified when
the function explicitly needs to modify them.
https://riptutorial.com/ 158
// Assume class Field, with member function "void insert_value(int);".
class ConstIncorrect {
Field fld;
public:
ConstIncorrect(Field& f); // Modifies.
class ConstCorrectCVQ {
Field fld;
public:
ConstCorrectCVQ(Field& f); // Modifies.
const Field& getField() const; // Doesn't modify. Exposes member as const reference,
// preventing indirect modification.
void setField(Field& f); // Modifies.
ConstCorrectCVQ::ConstCorrectCVQ(Field& f) : fld(f) {}
Field& ConstCorrectCVQ::getField() const { return fld; }
void ConstCorrectCVQ::setField(Field& f) { fld = f; }
void ConstCorrectCVQ::doSomething(int i) {
fld.insert_value(i);
}
void ConstCorrectCVQ::doNothing() const {}
https://riptutorial.com/ 159
We can then combine this with Const Correct Function Parameters, causing the class to be fully
const-correct.
class ConstCorrect {
Field fld;
public:
ConstCorrect(const Field& f); // Modifies instance. Doesn't modify parameter.
const Field& getField() const; // Doesn't modify. Exposes member as const reference,
// preventing indirect modification.
void setField(const Field& f); // Modifies instance. Doesn't modify parameter.
This can also be combined with overloading based on constness, in the case that we want one
behaviour if the instance is const, and a different behaviour if it isn't; a common use for this is
constainers providing accessors that only allow modification if the container itself is non-const.
class ConstCorrectContainer {
int arr[5];
public:
// Subscript operator provides read access if instance is const, or read/write access
// otherwise.
int& operator[](size_t index) { return arr[index]; }
const int& operator[](size_t index) const { return arr[index]; }
// ...
};
This is commonly used in the standard library, with most containers providing overloads to take
constness into account.
In a const-correct function, all passed-by-reference parameters are marked as const unless the
function directly or indirectly modifies them, preventing the programmer from inadvertently
changing something they didn't mean to change. This allows the function to take both const and
non-cv-qualified instances, and in turn, causes the instance's this to be of type const T* when a
member function is called, where T is the class' type.
struct Example {
https://riptutorial.com/ 160
void func() { std::cout << 3 << std::endl; }
void func() const { std::cout << 5 << std::endl; }
};
int main() {
Example a, b;
const_incorrect_function(a, &b);
const_correct_function(a, &b);
}
// Output:
3
3
5
5
While the effects of this are less immediately visible than those of const correct class design (in
that const-correct functions and const-incorrect classes will cause compilation errors, while const-
correct classes and const-incorrect functions will compile properly), const correct functions will
catch a lot of errors that const incorrect functions would let slip through, such as the one below.
[Note, however, that a const-incorrect function will cause compilation errors if passed a const
instance when it expected a non-const one.]
if (vals.size() && (vals_ind != -1) && (vals_ind < vals.size()) && !(h.needs_recalc())) {
return vals[h.get_cache_index(v_ind)];
}
T temp = v[v_ind];
temp -= h.poll_device();
temp *= h.obtain_random();
temp += h.do_tedious_calculation(temp, v[h.get_last_handled_index()]);
https://riptutorial.com/ 161
v.push_back(temp); // Oops. Should've been accessing vals.
vals_ind = vals.size() - 1;
h.register_index(v_ind, vals_ind);
}
return vals[vals_ind];
}
return vals[vals_ind];
}
One of the more useful things about const correctness is that it serves as a way of documenting
code, providing certain guarantees to the programmer and other users. These guarantees are
enforced by the compiler due to constness, with a lack of constness in turn indicating that code
doesn't provide them.
This can be used to make assumptions about the state of the object after any given member
function is called, even without seeing the definition of that function:
// ConstMemberFunctions.h
class ConstMemberFunctions {
https://riptutorial.com/ 162
int val;
mutable int cache;
mutable bool state_changed;
public:
// Constructor clearly changes logical state. No assumptions necessary.
ConstMemberFunctions(int v = 0);
// We can assume this function doesn't change logical state, and doesn't call
// set_val(). It may or may not call squared_calc() or bad_func().
int calc() const;
// We can assume this function doesn't change logical state, and doesn't call
// set_val(). It may or may not call calc() or bad_func().
int squared_calc() const;
// We can assume this function doesn't change logical state, and doesn't call
// set_val(). It may or may not call calc() or squared_calc().
void bad_func() const;
// We can assume this function changes logical state, and may or may not call
// calc(), squared_calc(), or bad_func().
void set_val(int v);
};
Due to const rules, these assumptions will in fact be enforced by the compiler.
// ConstMemberFunctions.cpp
ConstMemberFunctions::ConstMemberFunctions(int v /* = 0*/)
: cache(0), val(v), state_changed(true) {}
return cache;
}
https://riptutorial.com/ 163
const Function Parameters:
• Any function with one or more parameters which are const can be assumed to have intent to
read those parameters, and:
○Shall not modify those parameters, or call any member functions that would modify
them.
○Shall not pass those parameters to any other function which would modify them and/or
call any member functions that would modify them.
• Conversely, any function with one or more parameters which aren't const can be assumed to
have intent to modify those parameters, and:
○May or may not modify those parameters, or call any member functions which whould
modify them.
○May or may not pass those parameters to other functions which would modify them
and/or call any member functions that would modify them.
This can be used to make assumptions about the state of the parameters after being passed to
any given function, even without seeing the definition of that function.
// function_parameter.h
// We can assume that c isn't modified (and c.set_val() isn't called), and isn't passed
// to non_qualified_function_parameter(). If passed to one_const_one_not(), it is the first
// parameter.
void const_function_parameter(const ConstMemberFunctions& c);
// We can assume that c is modified and/or c.set_val() is called, and may or may not be passed
// to any of these functions. If passed to one_const_one_not, it may be either parameter.
void non_qualified_function_parameter(ConstMemberFunctions& c);
// We can assume that c isn't modified (and c.set_val() isn't called), and isn't passed
// to non_qualified_function_parameter(). If passed to one_const_one_not(), it is the first
// parameter.
void bad_parameter(const ConstMemberFunctions& c);
Due to const rules, these assumptions will in fact be enforced by the compiler.
// function_parameter.cpp
https://riptutorial.com/ 164
c.set_val(42);
std::cout << "For the value 42, the output is: " << c.calc() << '\n'
<< "If squared, it's: " << c.squared_calc()
<< std::endl;
}
const_function_parameter(l);
const_function_parameter(r);
}
While it is possible to circumvent const correctness, and by extension break these guarantees, this
must be done intentionally by the programmer (just like breaking encapsulation with Machiavelli,
above), and is likely to cause undefined behaviour.
// ...
However, due to this requiring the programmer to very specifically tell the compiler that they intend
to ignore constness, and being inconsistent across compilers, it is generally safe to assume that
const correct code will refrain from doing so unless otherwise specified.
https://riptutorial.com/ 165
Read Const Correctness online: https://riptutorial.com/cplusplus/topic/7217/const-correctness
https://riptutorial.com/ 166
Chapter 28: const keyword
Syntax
• const Type myVariable = initial; // Declares a const variable; cannot be changed
• const Type &myReference = myVariable; // Declares a reference to a const variable
• const Type *myPointer = &myVariable; // Declares a pointer-to-const. The pointer can
change, but the underlying data member cannot be changed through the pointer
• Type * const myPointer = &myVariable; // Declares a const pointer. The pointer cannot be
reassigned to point to something else, but the underlying data member can be changed
• const Type * const myPointer = &myVariable; // Declares a const pointer-to-const.
Remarks
A variable marked as const cannot1 be changed. Attempting to call any non-const operations on it
will result in a compiler error.
1: Well, it can be changed through const_cast, but you should almost never use that
Examples
Const local variables
int f = 0;
e = &f; // OK; e is a non-const pointer-to-const,
// which means that it can be rebound to new int* or const int*
int *g = &f;
*g = 1; // OK; this value still can be changed through dereferencing
// a pointer-not-to-const
https://riptutorial.com/ 167
Const pointers
int a = 0, b = 2;
pA = &b;
*pB = b;
Member functions of a class can be declared const, which tells the compiler and future readers
that this function will not modify the object:
class MyClass
{
private:
int myInt_;
public:
int myInt() const { return myInt_; }
void setMyInt(int myInt) { myInt_ = myInt; }
};
In a const member function, the this pointer is effectively a const MyClass * instead of a MyClass *.
This means that you cannot change any member variables within the function; the compiler will
emit a warning. So setMyInt could not be declared const.
You should almost always mark member functions as const when possible. Only const member
functions can be called on a const MyClass.
static methods cannot be declared as const. This is because a static method belongs to a class
and is not called on object; therefore it can never modify object's internal variables. So declaring
static methods as const would be redundant.
In C++ methods that differs only by const qualifier can be overloaded. Sometimes there may be a
need of two versions of getter that return a reference to some member.
https://riptutorial.com/ 168
Let Foo be a class, that has two methods that perform identical operations and returns a reference
to an object of type Bar:
class Foo
{
public:
Bar& GetBar(/* some arguments */)
{
/* some calculations */
return bar;
}
// ...
};
The only difference between them is that one method is non-const and return a non-const
reference (that can be use to modify object) and the second is const and returns const reference.
To avoid the code duplication, there is a temptation to call one method from another. However, we
can not call non-const method from the const one. But we can call const method from non-const
one. That will require as to use 'const_cast' to remove the const qualifier.
struct Foo
{
Bar& GetBar(/*arguments*/)
{
return const_cast<Bar&>(const_cast<const Foo*>(this)->GetBar(/*arguments*/));
}
In code above, we call const version of GetBar from the non-const GetBar by casting this to const
type: const_cast<const Foo*>(this). Since we call const method from non-const, the object itself is
non-const, and casting away the const is allowed.
#include <iostream>
class Student
{
public:
https://riptutorial.com/ 169
char& GetScore(bool midterm)
{
return const_cast<char&>(const_cast<const Student*>(this)->GetScore(midterm));
}
private:
char midtermScore;
char finalScore;
};
int main()
{
// non-const object
Student a;
// We can assign to the reference. Non-const version of GetScore is called
a.GetScore(true) = 'B';
a.GetScore(false) = 'A';
// const object
const Student b(a);
// We still can call GetScore method of const object,
// because we have overloaded const version of GetScore
std::cout << b.GetScore(true) << b.GetScore(false) << '\n';
}
https://riptutorial.com/ 170
Chapter 29: Constant class member
functions
Remarks
What does 'const member functions' of a class really means. The simple definition seems to be
that, a const member function cannot change the object. But what does 'can not change' really
means here. It simply means that you cannot do an assignment for class data members.
However, you can do other indirect operations like inserting an entry into a map as shown in the
example. Allowing this might look like this const function is modifying the object (yes, it does in
one sense), but it is allowed.
So, the real meaning is that a const member function cannot do an assignment for the class data
variables. But it can do other stuff like explained in the example.
Examples
constant member function
#include <iostream>
#include <map>
#include <string>
class A {
public:
map<string, string> * mapOfStrings;
public:
A() {
mapOfStrings = new map<string, string>();
}
void insertEntry(string const & key, string const & value) const {
(*mapOfStrings)[key] = value; // This works? Yes it does.
delete mapOfStrings; // This also works
mapOfStrings = new map<string, string>(); // This * does * not work
}
void refresh() {
delete mapOfStrings;
mapOfStrings = new map<string, string>(); // Works as refresh is non const function
}
https://riptutorial.com/ 171
A var;
var.insertEntry("abc", "abcValue");
var.getEntry("abc");
getchar();
return 0;
}
https://riptutorial.com/ 172
Chapter 30: constexpr
Introduction
constexpr is a keyword that can be used to mark a variable's value as a constant expression, a
function as potentially usable in constant expressions, or (since C++17) an if statement as having
only one of its branches selected to be compiled.
Remarks
The constexpr keyword was added in C++11 but for a few years since the C++11 standard was
published, not all major compilers supported it. at the time that the C++11 standard was published.
As of the time of publication of C++14, all major compilers support constexpr.
Examples
constexpr variables
A variable declared constexpr is implicitly const and its value may be used as a constant
expression.
A constexpr is type-safe replacement for #define based compile-time expressions. With constexpr
the compile-time evaluated expression is replaced with the result. For example:
C++11
int main()
{
constexpr int N = 10 + 2;
cout << N;
}
#define N 10 + 2
int main()
{
cout << N;
}
https://riptutorial.com/ 173
will produce:
cout << 10 + 2;
which will obviously be converted to cout << 10 + 2;. However, the compiler would have to do
more work. Also, it creates a problem if not used correctly.
cout << N * 2;
forms:
cout << 10 + 2 * 2; // 14
A const variable is a variable which needs memory for its storage. A constexpr does not. A
constexpr produces compile time constant, which cannot be changed. You may argue that const
may also not be changed. But consider:
int main()
{
const int size1 = 10;
const int size2 = abs(10);
int arr_one[size1];
int arr_two[size2];
}
With most compilers the second statement will fail (may work with GCC, for example). The size of
any array, as you might know, has to be a constant expression (i.e. results in compile-time value).
The second variable size2 is assigned some value that is decided at runtime (even though you
know it is 10, for the compiler it is not compile-time).
This means that a const may or may not be a true compile-time constant. You cannot guarantee or
enforce that a particular const value is absolutely compile-time. You may use #define but it has its
own pitfalls.
C++11
int main()
{
constexpr int size = 10;
int arr[size];
}
https://riptutorial.com/ 174
A constexpr expression must evaluate to a compile-time value. Thus, you cannot use:
C++11
C++11
C++11
constexpr functions
A function that is declared constexpr is implicitly inline and calls to such a function potentially yield
constant expressions. For example, the following function, if called with constant expression
arguments, yields a constant expression too:
C++11
Thus, the result of the function call may be used as an array bound or a template argument, or to
initialize a constexpr variable:
C++11
int main()
{
constexpr int S = Sum(10,20);
int Array[S];
int Array2[Sum(20,30)]; // 50 array size, compile time
}
Note that if you remove constexpr from function's return type specification, assignment to S will not
work, as S is a constexpr variable, and must be assigned a compile-time const. Similarly, size of
https://riptutorial.com/ 175
array will also not be a constant-expression, if function Sum is not constexpr.
Interesting thing about constexpr functions is that you may also use it like ordinary functions:
C++11
int a = 20;
auto sum = Sum(a, abs(-20));
Sumwill not be a constexpr function now, it will be compiled as an ordinary function, taking variable
(non-constant) arguments, and returning non-constant value. You need not to write two functions.
It also means that if you try to assign such call to a non-const variable, it won't compile:
C++11
int a = 20;
constexpr auto sum = Sum(a, abs(-20));
The reason is simple: constexpr must only be assigned a compile-time constant. However, the
above function call makes Sum a non-constexpr (R-value is non-const, but L-value is declaring itself
to be constexpr).
The constexpr function must also return a compile-time constant. Following will not compile:
C++11
Because a1 is a non-constexpr variable, and prohibits the function from being a true constexpr
function. Making it constexpr and assigning it a will also not work - since value of a (incoming
parameter) is still not yet known:
C++11
C++11
https://riptutorial.com/ 176
}
Since abs(a) is not a constant expression (even abs(10) will not work, since abs is not returning a
constexpr int !
C++11
We crafted our own Abs function which is a constexpr, and the body of Abs also doesn't break any
rule. Also, at the call site (inside Sum), the expression evaluates to a constexpr. Hence, the call to
Sum(-10, 20) will be a compile-time constant expression resulting to 30.
Static if statement
C++17
The if constexpr statement can be used to conditionally compile code. The condition must be a
constant expression. The branch not selected is discarded. A discarded statement inside a
template is not instantiated. For example:
In addition, variables and functions that are odr-used only inside discarded statements are not
required to be defined, and discarded return statements are not used for function return type
deduction.
if constexpr is distinct from #ifdef. #ifdef conditionally compiles code, but only based on
conditions that can be evaluated at preprocessing time. For example, #ifdef could not be used to
conditionally compile code depending on the value of a template parameter. On the other hand, if
constexpr cannot be used to discard syntactically invalid code, while #ifdef can.
if constexpr(false) {
foobar; // error; foobar has not been declared
std::vector<int> v("hello, world"); // error; no matching constructor
}
https://riptutorial.com/ 177
Read constexpr online: https://riptutorial.com/cplusplus/topic/3899/constexpr
https://riptutorial.com/ 178
Chapter 31: Copy Elision
Examples
Purpose of copy elision
There are places in the standard where an object is copied or moved in order to initialize an
object. Copy elision (sometimes called return value optimization) is an optimization whereby,
under certain specific circumstances, a compiler is permitted to avoid the copy or move even
though the standard says that it must happen.
std::string get_string()
{
return std::string("I am a string.");
}
According to the strict wording of the standard, this function will initialize a temporary std::string,
then copy/move that into the return value object, then destroy the temporary. The standard is very
clear that this is how the code is interpreted.
Copy elision is a rule that permits a C++ compiler to ignore the creation of the temporary and its
subsequent copy/destruction. That is, the compiler can take the initializing expression for the
temporary and initialize the function's return value from it directly. This obviously saves
performance.
1. The type must have the copy/move constructor that would have been called. Even if the
compiler elides the copy/move, the type must still be able to have been copied/moved.
C++11
struct my_type
{
my_type() = default;
my_type(const my_type &) {std::cout <<"Copying\n";}
my_type(my_type &&) {std::cout <<"Moving\n";}
};
my_type func()
{
return my_type();
}
https://riptutorial.com/ 179
What will calling func do? Well, it will never print "Copying", since the temporary is an rvalue and
my_type is a moveable type. So will it print "Moving"?
Without the copy elision rule, this would be required to always print "Moving". But because the
copy elision rule exists, the move constructor may or may not be called; it is implementation-
dependent.
And therefore, you cannot depend on the calling of copy/move constructors in contexts where
elision is possible.
Because elision is an optimization, your compiler may not support elision in all cases. And
regardless of whether the compiler elides a particular case or not, the type must still support the
operation being elided. So if a copy construction is elided, the type must still have a copy
constructor, even though it will not be called.
C++17
Normally, elision is an optimization. While virtually every compiler support copy elision in the
simplest of cases, having elision still places a particular burden on users. Namely, the type who's
copy/move is being elided must still have the copy/move operation that was elided.
For example:
std::mutex a_mutex;
std::lock_guard<std::mutex> get_lock()
{
return std::lock_guard<std::mutex>(a_mutex);
}
This might be useful in cases where a_mutex is a mutex that is privately held by some system, yet
an external user might want to have a scoped lock to it.
This is also not legal, because std::lock_guard cannot be copied or moved. Even though virtually
every C++ compiler will elide the copy/move, the standard still requires the type to have that
operation available.
Until C++17.
C++17 mandates elision by effectively redefining the very meaning of certain expressions so that
no copy/moving takes place. Consider the above code.
Under pre-C++17 wording, that code says to create a temporary and then use the temporary to
copy/move into the return value, but the temporary copy can be elided. Under C++17 wording, that
does not create a temporary at all.
In C++17, any prvalue expression, when used to initialize an object of the same type as the
expression, does not generate a temporary. The expression directly initializes that object. If you
return a prvalue of the same type as the return value, then the type need not have a copy/move
https://riptutorial.com/ 180
constructor. And therefore, under C++17 rules, the above code can work.
The C++17 wording works in cases where the prvalue's type matches the type being initialized. So
given get_lock above, this will also not require a copy/move:
Since the result of get_lock is a prvalue expression being used to initialize an object of the same
type, no copying or moving will happen. That expression never creates a temporary; it is used to
directly initialize the_lock. There is no elision because there is no copy/move to be elided elide.
The term "guaranteed copy elision" is therefore something of a misnomer, but that is the name of
the feature as it is proposed for C++17 standardization. It does not guarantee elision at all; it
eliminates the copy/move altogether, redefining C++ so that there never was a copy/move to be
elided.
This feature only works in cases involving a prvalue expression. As such, this uses the usual
elision rules:
std::mutex a_mutex;
std::lock_guard<std::mutex> get_lock()
{
std::lock_guard<std::mutex> my_lock(a_mutex);
//Do stuff
return my_lock;
}
While this is a valid case for copy elision, C++17 rules do not eliminate the copy/move in this case.
As such, the type must still have a copy/move constructor to use to initialize the return value. And
since lock_guard does not, this is still a compile error. Implementations are allowed to refuse to
elide copies when passing or returning an object of trivially-copyable type. This is to allow moving
such objects around in registers, which some ABIs might mandate in their calling conventions.
struct trivially_copyable {
int a;
};
If you return a prvalue expression from a function, and the prvalue expression has the same type
as the function's return type, then the copy from the prvalue temporary can be elided:
std::string func()
{
return std::string("foo");
}
https://riptutorial.com/ 181
Pretty much all compilers will elide the temporary construction in this case.
Parameter elision
When you pass an argument to a function, and the argument is a prvalue expression of the
function's parameter type, and this type is not a reference, then the prvalue's construction can be
elided.
func(std::string("foo"));
This says to create a temporary string, then move it into the function parameter str. Copy elision
permits this expression to directly create the object in str, rather than using a temporary+move.
This is a useful optimization for cases where a constructor is declared explicit. For example, we
could have written the above as func("foo"), but only because string has an implicit constructor
that converts from a const char* to a string. If that constructor was explicit, we would be forced to
use a temporary to call the explicit constructor. Copy elision saves us from having to do a
needless copy/move.
• represents an automatic variable local to that function, which will be destroyed after the
return
• the automatic variable is not a function parameter
• and the type of the variable is the same type as the function's return type
If all of these are the case, then the copy/move from the lvalue can be elided:
std::string func()
{
std::string str("foo");
//Do stuff
return str;
}
More complex cases are eligible for elision, but the more complex the case, the less likely the
compiler will be to actually elide it:
std::string func()
{
std::string ret("foo");
if(some_condition)
{
return "bar";
}
return ret;
}
https://riptutorial.com/ 182
The compiler could still elide ret, but the chances of them doing so go down.
If you use a prvalue expression to copy initialize a variable, and that variable has the same type as
the prvalue expression, then the copying can be elided.
Copy initialization effectively transforms this into std::string str("foo"); (there are minor
differences).
std::string func()
{
return std::string("foo");
}
Without copy elision, this would provoke 2 calls to std::string's move constructor. Copy elision
permits this to call the move constructor 1 or zero times, and most compilers will opt for the latter.
https://riptutorial.com/ 183
Chapter 32: Copying vs Assignment
Syntax
• Copy Constructor
• MyClass( const MyClass& other );
• MyClass( MyClass& other );
• MyClass( volatile const MyClass& other );
• MyClass( volatile MyClass& other );
• Assignment Constructor
• MyClass& operator=( const MyClass& rhs );
• MyClass& operator=( MyClass& rhs );
• MyClass& operator=( MyClass rhs );
• const MyClass& operator=( const MyClass& rhs );
• const MyClass& operator=( MyClass& rhs );
• const MyClass& operator=( MyClass rhs );
• MyClass operator=( const MyClass& rhs );
• MyClass operator=( MyClass& rhs );
• MyClass operator=( MyClass rhs );
Parameters
Right Hand Side of the equality for both copy and assignment
rhs constructors. For example the assignment constructor : MyClass
operator=( MyClass& rhs );
Placeholder Placeholder
Remarks
Other Good Resources for further research :
GeeksForGeeks
C++ Articles
Examples
Assignment Operator
https://riptutorial.com/ 184
The Assignment Operator is when you replace the data with an already existing(previously
initialized) object with some other object's data. Lets take this as an example:
// Assignment Operator
#include <iostream>
#include <string>
using std::cout;
using std::endl;
class Foo
{
public:
Foo(int data)
{
this->data = data;
}
~Foo(){};
Foo& operator=(const Foo& rhs)
{
data = rhs.data;
return *this;
}
int data;
};
int main()
{
Foo foo(2); //Foo(int data) called
Foo foo2(42);
foo = foo2; // Assignment Operator Called
cout << foo.data << endl; //Prints 42
}
You can see here I call the assignment operator when I already initialized the foo object. Then
later I assign foo2 to foo . All the changes to appear when you call that equal sign operator is
defined in your operator= function. You can see a runnable output here: http://cpp.sh/3qtbm
Copy Constructor
Copy constructor on the other hand , is the complete opposite of the Assignment Constructor. This
time, it is used to initialize an already nonexistent(or non-previously initialized) object. This means
it copies all the data from the object you are assigning it to , without actually initializing the object
that is being copied onto. Now Let's take a look at the same code as before but modify the
assignment constructor to be a copy constructor :
// Copy Constructor
#include <iostream>
#include <string>
using std::cout;
using std::endl;
class Foo
{
https://riptutorial.com/ 185
public:
Foo(int data)
{
this->data = data;
}
~Foo(){};
Foo(const Foo& rhs)
{
data = rhs.data;
}
int data;
};
int main()
{
Foo foo(2); //Foo(int data) called
Foo foo2 = foo; // Copy Constructor called
cout << foo2.data << endl;
}
You can see here Foo foo2 = foo; in the main function I immediately assign the object before
actually initializing it, which as said before means it's a copy constructor. And notice that I didn't
need to pass the parameter int for the foo2 object since I automatically pulled the previous data
from the object foo. Here is an example output : http://cpp.sh/5iu7
Ok we have briefly looked over what the copy constructor and assignment constructor are above
and gave examples of each now let's see both of them in the same code. This code will be similar
as above two. Let's take this :
using std::cout;
using std::endl;
class Foo
{
public:
Foo(int data)
{
this->data = data;
}
~Foo(){};
Foo(const Foo& rhs)
{
data = rhs.data;
}
https://riptutorial.com/ 186
int data;
};
int main()
{
Foo foo(2); //Foo(int data) / Normal Constructor called
Foo foo2 = foo; //Copy Constructor Called
cout << foo2.data << endl;
Foo foo3(42);
foo3=foo; //Assignment Constructor Called
cout << foo3.data << endl;
}
Output:
2
2
Here you can see we first call the copy constructor by executing the line Foo foo2 = foo; . Since
we didn't initialize it previously. And then next we call the assignment operator on foo3 since it was
already initialized foo3=foo;
https://riptutorial.com/ 187
Chapter 33: Curiously Recurring Template
Pattern (CRTP)
Introduction
A pattern in which a class inherits from a class template with itself as one of its template
parameters. CRTP is usually used to provide static polymorphism in C++.
Examples
The Curiously Recurring Template Pattern (CRTP)
CRTP is a powerful, static alternative to virtual functions and traditional inheritance that can be
used to give types properties at compile time. It works by having a base class template which
takes, as one of its template parameters, the derived class. This permits it to legally perform a
static_cast of its this pointer to the derived class.
Of course, this also means that a CRTP class must always be used as the base class of some
other class. And the derived class must pass itself to the base class.
C++14
Let's say you have a set of containers that all support the functions begin() and end(). The
standard library's requirements for containers require more functionality. We can design a CRTP
base class that provides that functionality, based solely on begin() and end():
#include <iterator>
template <typename Sub>
class Container {
private:
// self() yields a reference to the derived type
Sub& self() { return *static_cast<Sub*>(this); }
Sub const& self() const { return *static_cast<Sub const*>(this); }
public:
decltype(auto) front() {
return *self().begin();
}
decltype(auto) back() {
return *std::prev(self().end());
}
decltype(auto) operator[](std::size_t i) {
return *std::next(self().begin(), i);
https://riptutorial.com/ 188
}
};
The above class provides the functions front(), back(), size(), and operator[] for any subclass
which provides begin() and end(). An example subclass is a simple dynamically allocated array:
#include <memory>
// A dynamically allocated array
template <typename T>
class DynArray : public Container<DynArray<T>> {
public:
using Base = Container<DynArray<T>>;
DynArray(std::size_t size)
: size_{size},
data_{std::make_unique<T[]>(size_)}
{ }
private:
std::size_t size_;
std::unique_ptr<T[]> data_;
};
Users of the DynArray class can use the interfaces provided by the CRTP base class easily as
follows:
DynArray<int> arr(10);
arr.front() = 2;
arr[2] = 5;
assert(arr.size() == 10);
Usefulness: This pattern particularly avoids virtual function calls at run-time which occur to
traverse down the inheritance hierarchy and simply relies on static casts:
DynArray<int> arr(10);
DynArray<int>::Base & base = arr;
base.begin(); // no virtual calls
The only static cast inside the function begin() in the base class Container<DynArray<int>> allows
the compiler to drastically optimize the code and no virtual table look up happens at runtime.
Limitations: Because the base class is templated and different for two different DynArrays it is not
possible to store pointers to their base classes in an type-homogenous array as one could
generally do with normal inheritance where the base class is not dependent on the derived type:
class A {};
class B: public A{};
A* a = new B;
https://riptutorial.com/ 189
CRTP to avoid code duplication
struct IShape
{
virtual ~IShape() = default;
Each child type of IShape needs to implement the same function the same way. That's a lot of extra
typing. Instead, we can introduce a new type in the hierarchy that does this for us:
And now, each shape simply needs to inherit from the acceptor:
https://riptutorial.com/ 190
Read Curiously Recurring Template Pattern (CRTP) online:
https://riptutorial.com/cplusplus/topic/9269/curiously-recurring-template-pattern--crtp-
https://riptutorial.com/ 191
Chapter 34: Data Structures in C++
Examples
Linked List implementation in C++
class listNode
{
public:
int data;
listNode *next;
listNode(int val):data(val),next(NULL){}
};
class List
{
public:
listNode *head;
List():head(NULL){}
void insertAtBegin(int val);
void insertAtEnd(int val);
void insertAtPos(int val);
void remove(int val);
void print();
~List();
};
https://riptutorial.com/ 192
{
ptr=ptr->next;
}
ptr->next=newnode;
}
https://riptutorial.com/ 193
{
listNode *ptr=this->head;
while(ptr!=NULL)
{
cout<<ptr->data<<" " ;
ptr=ptr->next;
}
cout<<endl;
}
List::~List()
{
listNode *ptr=this->head,*next=NULL;
while(ptr!=NULL)
{
next=ptr->next;
delete(ptr);
ptr=next;
}
}
https://riptutorial.com/ 194
Chapter 35: Date and time using header
Examples
Measuring time using
The system_clock can be used to measure the time elapsed during some part of a program's
execution.
c++11
#include <iostream>
#include <chrono>
#include <thread>
int main() {
auto start = std::chrono::system_clock::now(); // This and "end"'s type is
std::chrono::time_point
{ // The code to test
std::this_thread::sleep_for(std::chrono::seconds(2));
}
auto end = std::chrono::system_clock::now();
In this example, sleep_for was used to make the active thread sleep for a time period measured in
std::chrono::seconds, but the code between braces could be any function call that takes some time
to execute.
This example shows how to find number of days between two dates. A date is specified by
year/month/day of month, and additionally hour/minute/second.
#include <iostream>
#include <string>
#include <chrono>
#include <ctime>
/***
* Creates a std::tm structure from raw date.
*
* \param year (must be 1900 or greater)
* \param month months since January – [1, 12]
* \param day day of the month – [1, 31]
* \param minutes minutes after the hour – [0, 59]
* \param seconds seconds after the minute – [0, 61](until C++11) / [0, 60] (since C++11)
*
https://riptutorial.com/ 195
* Based on http://en.cppreference.com/w/cpp/chrono/c/tm
*/
std::tm CreateTmStruct(int year, int month, int day, int hour, int minutes, int seconds) {
struct tm tm_ret = {0};
tm_ret.tm_sec = seconds;
tm_ret.tm_min = minutes;
tm_ret.tm_hour = hour;
tm_ret.tm_mday = day;
tm_ret.tm_mon = month - 1;
tm_ret.tm_year = year - 1900;
return tm_ret;
}
return diff_in_days.count();
}
int main()
{
for ( int year = 2000; year <= 2016; ++year )
std::cout << "There are " << get_days_in_year(year) << " days in " << year << "\n";
}
https://riptutorial.com/ 196
Chapter 36: decltype
Introduction
The keyword decltype can be used to get the type of a variable, function or an expression.
Examples
Basic Example
int a = 10;
float a=99.0f;
Another example
std::vector<int> intVector;
And we want to declare an iterator for this vector. An obvious idea is to use auto. However, it may
be needed just declare an iterator variable (and not to assign it to anything). We would do:
vector<int>::iterator iter;
However, with decltype it becomes easy and less error prone (if type of intVector changes).
decltype(intVector)::iterator iter;
Alternatively:
decltype(intVector.begin()) iter;
In second example, the return type of begin is used to determine the actual type, which is
https://riptutorial.com/ 197
vector<int>::iterator.
https://riptutorial.com/ 198
Chapter 37: Design pattern implementation in
C++
Introduction
On this page, you can find examples of how design patterns are implemented in C++. For the
details on these patterns, you can check out the design patterns documentation.
Remarks
A design pattern is a general reusable solution to a commonly occurring problem within a given
context in software design.
Examples
Observer pattern
Observer Pattern's intent is to define a one-to-many dependency between objects so that when
one object changes state, all its dependents are notified and updated automatically.
The subject and observers define the one-to-many relationship. The observers are dependent on
the subject such that when the subject's state changes, the observers get notified. Depending on
the notification, the observers may also be updated with new values.
#include <iostream>
#include <vector>
class Subject;
class Observer
{
public:
virtual ~Observer() = default;
virtual void Update(Subject&) = 0;
};
class Subject
{
public:
virtual ~Subject() = default;
void Attach(Observer& o) { observers.push_back(&o); }
void Detach(Observer& o)
{
observers.erase(std::remove(observers.begin(), observers.end(), &o));
}
void Notify()
{
https://riptutorial.com/ 199
for (auto* o : observers) {
o->Update(*this);
}
}
private:
std::vector<Observer*> observers;
};
Notify();
}
private:
int hour;
int minute;
int second;
};
void Draw()
{
int hour = subject.GetHour();
int minute = subject.GetMinute();
int second = subject.GetSecond();
private:
ClockTimer& subject;
};
https://riptutorial.com/ 200
explicit AnalogClock(ClockTimer& s) : subject(s) { subject.Attach(*this); }
~AnalogClock() { subject.Detach(*this); }
void Update(Subject& theChangedSubject) override
{
if (&theChangedSubject == &subject) {
Draw();
}
}
void Draw()
{
int hour = subject.GetHour();
int minute = subject.GetMinute();
int second = subject.GetSecond();
int main()
{
ClockTimer timer;
DigitalClock digitalClock(timer);
AnalogClock analogClock(timer);
Output:
1. Objects (DigitalClock or AnalogClock object) use the Subject interfaces (Attach() or Detach())
either to subscribe (register) as observers or unsubscribe (remove) themselves from being
observers (subject.Attach(*this); , subject.Detach(*this);.
3. All observers need to implement the Observer interface. This interface just has one method,
Update(), that gets called when the Subject's state changes (Update(Subject &))
4. In addition to the Attach() and Detach() methods, the concrete subject implements a Notify()
method that is used to update all the current observers whenever state changes. But in this
case, all of them are done in the parent class, Subject (Subject::Attach (Observer&), void
Subject::Detach(Observer&) and void Subject::Notify() .
5. The Concrete object may also have methods for setting and getting its state.
https://riptutorial.com/ 201
6. Concrete observers can be any class that implements the Observer interface. Each observer
subscribe (register) with a concrete subject to receive update (subject.Attach(*this); ).
7. The two objects of Observer Pattern are loosely coupled, they can interact but with little
knowledge of each other.
Variation:
Signals and slots is a language construct introduced in Qt, which makes it easy to implement the
Observer pattern while avoiding boilerplate code. The concept is that controls (also known as
widgets) can send signals containing event information which can be received by other controls
using special functions known as slots. The slot in Qt must be a class member declared as such.
The signal/slot system fits well with the way Graphical User Interfaces are designed. Similarly, the
signal/slot system can be used for asynchronous I/O (including sockets, pipes, serial devices, etc.)
event notification or to associate timeout events with appropriate object instances and methods or
functions. No registration/deregistration/invocation code need be written, because Qt's Meta
Object Compiler (MOC) automatically generates the needed infrastructure.
The C# language also supports a similar construct although with a different terminology and
syntax: events play the role of signals, and delegates are the slots. Additionally, a delegate can be
a local variable, much like a function pointer, while a slot in Qt must be a class member declared
as such.
Adapter Pattern
Convert the interface of a class into another interface clients expect. Adapter (or Wrapper) lets
classes work together that couldn't otherwise because of incompatible interfaces. Adapter
pattern's motivation is that we can reuse existing software if we can modify the interface.
4. In STL, stack adapted from vector: When stack executes push(), underlying vector does
vector::push_back().
Example:
#include <iostream>
https://riptutorial.com/ 202
// Legacy component (Adaptee)
class LegacyRectangle
{
public:
LegacyRectangle(int x1, int y1, int x2, int y2) {
x1_ = x1;
y1_ = y1;
x2_ = x2;
y2_ = y2;
std::cout << "LegacyRectangle(x1,y1,x2,y2)\n";
}
void oldDraw() {
std::cout << "LegacyRectangle: oldDraw(). \n";
}
private:
int x1_;
int y1_;
int x2_;
int y2_;
};
// Adapter wrapper
class RectangleAdapter: public Rectangle, private LegacyRectangle
{
public:
RectangleAdapter(int x, int y, int w, int h):
LegacyRectangle(x, y, x + w, y + h) {
std::cout << "RectangleAdapter(x,y,x+w,x+h)\n";
}
void draw() {
std::cout << "RectangleAdapter: draw().\n";
oldDraw();
}
};
int main()
{
int x = 20, y = 50, w = 300, h = 200;
Rectangle *r = new RectangleAdapter(x,y,w,h);
r->draw();
}
//Output:
//LegacyRectangle(x1,y1,x2,y2)
//RectangleAdapter(x,y,x+w,x+h)
2. The target is the Rectangle class. This is what the client invokes method on.
https://riptutorial.com/ 203
class RectangleAdapter: public Rectangle, private LegacyRectangle {
...
}
5. The LegacyRectangle class does not have the same methods (draw()) as Rectangle, but the
Adapter(RectangleAdapter) can take the Rectangle method calls and turn around and invoke
method on the LegacyRectangle, oldDraw().
void draw() {
std::cout << "RectangleAdapter: draw().\n";
oldDraw();
}
};
Adapter design pattern translates the interface for one class into a compatible but different
interface. So, this is similar to the proxy pattern in that it's a single-component wrapper. But the
interface for the adapter class and the original class may be different.
As we've seen in the example above, this adapter pattern is useful to expose a different interface
for an existing API to allow it to work with other code. Also, by using adapter pattern, we can take
heterogeneous interfaces, and transform them to provide consistent API.
Bridge pattern has a structure similar to an object adapter, but Bridge has a different intent: It is
meant to separate an interface from its implementation so that they can be varied easily and
independently. An adapter is meant to change the interface of an existing object.
Factory Pattern
Factory pattern decouples object creation and allows creation by name using a common interface:
class Animal{
public:
virtual std::shared_ptr<Animal> clone() const = 0;
virtual std::string getname() const = 0;
};
https://riptutorial.com/ 204
{
return "bear";
}
};
class AnimalFactory{
public:
static std::shared_ptr<Animal> getAnimal( const std::string& name )
{
if ( name == "bear" )
return std::make_shared<Bear>();
if ( name == "cat" )
return std::shared_ptr<Cat>();
return nullptr;
}
};
The Builder Pattern decouples the creation of the object from the object itself. The main idea
behind is that an object does not have to be responsible for its own creation. The correct and
valid assembly of a complex object may be a complicated task in itself, so this task can be
delegated to another class.
Inspired by the Email Builder in C#, I've decided to make a C++ version here. An Email object is
not necessarily a very complex object, but it can demonstrate the pattern.
#include <iostream>
#include <sstream>
#include <string>
class Email
{
public:
friend class EmailBuilder; // the builder can access Email's privates
https://riptutorial.com/ 205
static EmailBuilder make();
private:
Email() = default; // restrict construction to builder
string m_from;
string m_to;
string m_subject;
string m_body;
};
class EmailBuilder
{
public:
EmailBuilder& from(const string &from) {
m_email.m_from = from;
return *this;
}
operator Email&&() {
return std::move(m_email); // notice the move
}
private:
Email m_email;
};
EmailBuilder Email::make()
{
return EmailBuilder();
}
// Bonus example!
std::ostream& operator <<(std::ostream& stream, const Email& email)
{
stream << email.to_string();
return stream;
https://riptutorial.com/ 206
}
int main()
{
Email mail = Email::make().from("[email protected]")
.to("[email protected]")
.subject("C++ builders")
.body("I like this API, don't you?");
For older versions of C++, one may just ignore the std::move operation and remove the && from
the conversion operator (although this will create a temporary copy).
The builder finishes its work when it releases the built email by the operator Email&&(). In this
example, the builder is a temporary object and returns the email before being destroyed. You
could also use an explicit operation like Email EmailBuilder::build() {...} instead of the
conversion operator.
int main()
{
EmailBuilder builder;
add_addresses(builder);
compose_mail(builder);
https://riptutorial.com/ 207
You can change the design of this pattern to fit your needs. I'll give one variant.
In the given example the Email object is immutable, i.e., it's properties can't be modified because
there is no access to them. This was a desired feature. If you need to modify the object after its
creation you have to provide some setters to it. Since those setters would be duplicated in the
builder, you may consider to do it all in one class (no builder class needed anymore).
Nevertheless, I would consider the need to make the built object mutable in the first place.
https://riptutorial.com/ 208
Chapter 38: Digit separators
Examples
Digit Separator
• Pronounce 7237498123.
• Compare 237498123 with 237499123 for equality.
• Decide whether 237499123 or 20249472 is larger.
C++14 define Simple Quotation Mark ' as a digit separator, in numbers and user-defined literals.
This can make it easier for human readers to parse large numbers.
C++14
Example:
• The literals 1048576, 1'048'576, 0X100000, 0x10'0000, and 0'004'000'000 all have the same
value.
• The literals 1.602'176'565e-19 and 1.602176565e-19 have the same value.
The position of the single quotes is irrelevant. All the following are equivalent:
C++14
C++14
https://riptutorial.com/ 209
Chapter 39: Enumeration
Examples
Basic Enumeration Declaration
Standard enumerations allow users to declare a useful name for a set of integers. The names are
collectively referred to as enumerators. An enumeration and its associated enumerators are
defined as follows:
enum myEnum
{
enumName1,
enumName2,
};
An enumeration is a type, one which is distinct from all other types. In this case, the name of this
type is myEnum. Objects of this type are expected to assume the value of an enumerator within the
enumeration.
The enumerators declared within the enumeration are constant values of the type of the
enumeration. Though the enumerators are declared within the type, the scope operator :: is not
needed to access the name. So the name of the first enumerator is enumName1.
C++11
The scope operator can be optionally used to access an enumerator within an enumeration. So
enumName1 can also be spelled myEnum::enumName1.
Enumerators are assigned integer values starting from 0 and increasing by 1 for each enumerator
in an enumeration. So in the above case, enumName1 has the value 0, while enumName2 has the value
1.
Enumerators can also be assigned a specific value by the user; this value must be an integral
constant expression. Enumerators who's values are not explicitly provided will have their value set
to the value of the previous enumerator + 1.
enum myEnum
{
enumName1 = 1, // value will be 1
enumName2 = 2, // value will be 2
enumName3, // value will be 3, previous value + 1
enumName4 = 7, // value will be 7
enumName5, // value will be 8
enumName6 = 5, // value will be 5, legal to go backwards
enumName7 = 3, // value will be 3, legal to reuse numbers
enumName8 = enumName4 + 2, // value will be 9, legal to take prior enums and adjust them
};
https://riptutorial.com/ 210
Enumeration in switch statements
A common use for enumerators is for switch statements and so they commonly appear in state
machines. In fact a useful feature of switch statements with enumerations is that if no default
statement is included for the switch, and not all values of the enum have been utilized, the
compiler will issue a warning.
enum State {
start,
middle,
end
};
...
switch(myState) {
case start:
...
case middle:
...
} // warning: enumeration value 'end' not handled in switch [-Wswitch]
enum E {
Begin,
E1 = Begin,
E2,
// ..
En,
End
};
C++11
https://riptutorial.com/ 211
}
enum E {
E1 = 4,
E2 = 8,
// ..
En
};
std::vector<E> build_all_E()
{
const E all[] = {E1, E2, /*..*/ En};
and then
C++11
enum E {
E1 = 4,
E2 = 8,
// ..
En
};
and then
Scoped enums
C++11 introduces what are known as scoped enums. These are enumerations whose members
must be qualified with enumname::membername. Scoped enums are declared using the enum class
syntax. For example, to store the colors in a rainbow:
https://riptutorial.com/ 212
RED,
ORANGE,
YELLOW,
GREEN,
BLUE,
INDIGO,
VIOLET
};
rainbow r = rainbow::INDIGO;
enum classes cannot be implicitly converted to ints without a cast. So int x = rainbow::RED is
invalid.
Scoped enums also allow you to specify the underlying type, which is the type used to represent a
member. By default it is int. In a Tic-Tac-Toe game, you may store the piece as
As you may notice, enums can have a trailing comma after the last member.
Scoped enumerations:
...
enum class Status; // Forward declaration
Status doWork(); // Use the forward declaration
...
enum class Status { Invalid, Success, Fail };
Status doWork() // Full declaration required for implementation
{
return Status::Success;
}
Unscoped enumerations:
...
enum Status: int; // Forward declaration, explicit type required
Status doWork(); // Use the forward declaration
...
enum Status: int{ Invalid=0, Success, Fail }; // Must match forward declare type
static_assert( Success == 1 );
An in-depth multi-file example can be found here: Blind fruit merchant example
https://riptutorial.com/ 213
Chapter 40: Exceptions
Examples
Catching exceptions
A try/catch block is used to catch exceptions. The code in the try section is the code that may
throw an exception, and the code in the catch clause(s) handles the exception.
#include <iostream>
#include <string>
#include <stdexcept>
int main() {
std::string str("foo");
try {
str.at(10); // access element, may throw std::out_of_range
} catch (const std::out_of_range& e) {
// what() is inherited from std::exception and contains an explanatory message
std::cout << e.what();
}
}
Multiple catch clauses may be used to handle multiple exception types. If multiple catch clauses
are present, the exception handling mechanism tries to match them in order of their appearance
in the code:
std::string str("foo");
try {
str.reserve(2); // reserve extra capacity, may throw std::length_error
str.at(10); // access element, may throw std::out_of_range
} catch (const std::length_error& e) {
std::cout << e.what();
} catch (const std::out_of_range& e) {
std::cout << e.what();
}
Exception classes which are derived from a common base class can be caught with a single catch
clause for the common base class. The above example can replace the two catch clauses for
std::length_error and std::out_of_range with a single clause for std:exception:
std::string str("foo");
try {
str.reserve(2); // reserve extra capacity, may throw std::length_error
str.at(10); // access element, may throw std::out_of_range
} catch (const std::exception& e) {
std::cout << e.what();
}
https://riptutorial.com/ 214
Because the catch clauses are tried in order, be sure to write more specific catch clauses first,
otherwise your exception handling code might never get called:
try {
/* Code throwing exceptions omitted. */
} catch (const std::exception& e) {
/* Handle all exceptions of type std::exception. */
} catch (const std::runtime_error& e) {
/* This block of code will never execute, because std::runtime_error inherits
from std::exception, and all exceptions of type std::exception were already
caught by the previous catch clause. */
}
Another possibility is the catch-all handler, which will catch any thrown object:
try {
throw 10;
} catch (...) {
std::cout << "caught an exception";
}
Sometimes you want to do something with the exception you catch (like write to log or print a
warning) and let it bubble up to the upper scope to be handled. To do so, you can rethrow any
exception you catch:
try {
... // some code here
} catch (const SomeException& e) {
std::cout << "caught an exception";
throw;
}
Using throw; without arguments will re-throw the currently caught exception.
C++11
To rethrow a managed std::exception_ptr, the C++ Standard Library has the rethrow_exception
function that can be used by including the <exception> header in your program.
#include <iostream>
#include <string>
#include <exception>
#include <stdexcept>
https://riptutorial.com/ 215
}
}
int main()
{
std::exception_ptr eptr;
try {
std::string().at(1); // this generates an std::out_of_range
} catch(...) {
eptr = std::current_exception(); // capture
}
handle_eptr(eptr);
} // destructor for std::out_of_range called here, when the eptr is destructed
struct A : public B
{
A() try : B(), foo(1), bar(2)
{
// constructor body
}
catch (...)
{
// exceptions from the initializer list and constructor are caught here
// if no exception is thrown here
// then the caught exception is re-thrown.
}
private:
Foo foo;
Bar bar;
};
void function_with_try_block()
try
{
// try block body
}
catch (...)
{
// catch block body
}
Which is equivalent to
void function_with_try_block()
{
try
{
// try block body
}
https://riptutorial.com/ 216
catch (...)
{
// catch block body
}
}
Note that for constructors and destructors, the behavior is different as the catch block re-throws an
exception anyway (the caught one if there is no other throw in the catch block body).
The function main is allowed to have a function try block like any other function, but main's function
try block will not catch exceptions that occur during the construction of a non-local static variable
or the destruction of any static variable. Instead, std::terminate is called.
struct A
{
~A() noexcept(false) try
{
// destructor body
}
catch (...)
{
// exceptions of destructor body are caught here
// if no exception is thrown here
// then the caught exception is re-thrown.
}
};
Note that, although this is possible, one needs to be very careful with throwing from destructor, as
if a destructor called during stack unwinding throws an exception, std::terminate is called.
In general, it is considered good practice to throw by value (rather than by pointer), but catch by
(const) reference.
try {
// throw new std::runtime_error("Error!"); // Don't do this!
// This creates an exception object
// on the heap and would require you to catch the
// pointer and manage the memory yourself. This can
// cause memory leaks!
throw std::runtime_error("Error!");
} catch (const std::runtime_error& e) {
std::cout << e.what() << std::endl;
}
One reason why catching by reference is a good practice is that it eliminates the need to
reconstruct the object when being passed to the catch block (or when propagating through to other
catch blocks). Catching by reference also allows the exceptions to be handled polymorphically and
avoids object slicing. However, if you are rethrowing an exception (like throw e;, see example
https://riptutorial.com/ 217
below), you can still get object slicing because the throw e; statement makes a copy of the
exception as whatever type is declared:
#include <iostream>
struct BaseException {
virtual const char* what() const { return "BaseException"; }
};
If you are sure that you are not going to do anything to change the exception (like add information
or modify the message), catching by const reference allows the compiler to make optimizations
and can improve performance. But this can still cause object splicing (as seen in the example
above).
Nested exception
C++11
During exception handling there is a common use case when you catch a generic exception from
a low-level function (such as a filesystem error or data transfer error) and throw a more specific
high-level exception which indicates that some high-level operation could not be performed (such
as being unable to publish a photo on Web). This allows exception handling to react to specific
problems with high level operations and also allows, having only error an message, the
programmer to find a place in the application where an exception occurred. Downside of this
solution is that exception callstack is truncated and original exception is lost. This forces
developers to manually include text of original exception into a newly created one.
https://riptutorial.com/ 218
Nested exceptions aim to solve the problem by attaching low-level exception, which describes the
cause, to a high level exception, which describes what it means in this particular case.
#include <stdexcept>
#include <exception>
#include <string>
#include <fstream>
#include <iostream>
struct MyException
{
MyException(const std::string& message) : message(message) {}
std::string message;
};
https://riptutorial.com/ 219
// sample function that catches an exception and wraps it in a nested exception
void run()
{
try {
open_file("nonexistent.file");
} catch(...) {
std::throw_with_nested( std::runtime_error("run() failed") );
}
}
// runs the sample function above and prints the caught exception
int main()
{
try {
run();
} catch(...) {
print_current_exception_with_nested();
}
}
Possible output:
If you work only with exceptions inherited from std::exception, code can even be simplified.
std::uncaught_exceptions
c++17
#include <exception>
#include <string>
#include <iostream>
// ...
~Transaction() {
https://riptutorial.com/ 220
if (uncaughtExceptionCount == std::uncaught_exceptions()) {
Commit(); // May throw.
} else { // current stack unwinding
RollBack();
}
}
private:
std::string message;
int uncaughtExceptionCount = std::uncaught_exceptions();
};
class Foo
{
public:
~Foo() {
try {
Transaction transaction("In ~Foo"); // Commit,
// even if there is an uncaught exception
//...
} catch (const std::exception& e) {
std::cerr << "exception/~Foo:" << e.what() << std::endl;
}
}
};
int main()
{
try {
Transaction transaction("In main"); // RollBack
Foo foo; // ~Foo commit its transaction.
//...
throw std::runtime_error("Error");
} catch (const std::exception& e) {
std::cerr << "exception/main:" << e.what() << std::endl;
}
}
Output:
In ~Foo: Commit
In main: Rollback
exception/main:Error
Custom exception
You shouldn't throw raw values as exceptions, instead use one of the standard exception classes
or make your own.
Having your own exception class inherited from std::exception is a good way to go about it. Here's
a custom exception class which directly inherits from std::exception:
#include <exception>
protected:
https://riptutorial.com/ 221
int error_number; ///< Error number
int error_offset; ///< Error offset
std::string error_message; ///< Error message
public:
/** Destructor.
* Virtual to allow for subclassing.
*/
virtual ~Except() throw () {}
};
try {
throw(Except("Couldn't do what you were expecting", -12, -34));
} catch (const Except& e) {
std::cout<<e.what()
<<"\nError number: "<<e.getErrorNumber()
<<"\nError offset: "<<e.getErrorOffset();
}
https://riptutorial.com/ 222
As you are not only just throwing a dumb error message, also some other values representing
what the error exactly was, your error handling becomes much more efficient and meaningful.
There's an exception class that let's you handle error messages nicely :std::runtime_error
#include <stdexcept>
protected:
public:
/** Destructor.
* Virtual to allow for subclassing.
*/
virtual ~Except() throw () {}
};
Note that I haven't overridden the what() function from the base class (std::runtime_error) i.e we
will be using the base class's version of what(). You can override it if you have further agenda.
https://riptutorial.com/ 223
Chapter 41: Explicit type conversions
Introduction
An expression can be explicitly converted or cast to type T using dynamic_cast<T>, static_cast<T>,
reinterpret_cast<T>, or const_cast<T>, depending on what type of cast is intended.
C++ also supports function-style cast notation, T(expr), and C-style cast notation, (T)expr.
Syntax
• simple-type-specifier ( )
• simple-type-specifier ( expression-list )
• simple-type-specifier braced-init-list
• typename-specifier ( )
• typename-specifier ( expression-list )
• typename-specifier braced-init-list
• dynamic_cast < type-id > ( expression )
• static_cast < type-id > ( expression )
• reinterpret_cast < type-id > ( expression )
• const_cast < type-id > ( expression )
• ( type-id ) cast-expression
Remarks
All six cast notations have one thing in common:
The reinterpret_cast keyword is responsible for performing two different kinds of "unsafe"
conversions:
• The "type punning" conversions, which can be used to access memory of one type as
though it is of a different type.
• Conversions between integer types and pointer types, in either direction.
https://riptutorial.com/ 224
• Any conversion that can be done by a direct initialization, including both implicit conversions
and conversions that call an explicit constructor or conversion function. See here and here
for more details.
• Between arithmetic and enumeration types, and between different enumeration types. See
enum conversions
• From pointer to member of derived class, to pointer to member of base class. The types
pointed to must match. See derived to base conversion for pointers to members
• void* to T*.
C++11
Examples
Base to derived conversion
A pointer to base class can be converted to a pointer to derived class using static_cast.
static_cast does not do any run-time checking and can lead to undefined behaviour when the
pointer does not actually point to the desired type.
Likewise, a reference to base class can be converted to a reference to derived class using
static_cast.
If the source type is polymorphic, dynamic_cast can be used to perform a base to derived
https://riptutorial.com/ 225
conversion. It performs a run-time check and failure is recoverable instead of producing undefined
behaviour. In the pointer case, a null pointer is returned upon failure. In the reference case, an
exception is thrown upon failure of type std::bad_cast (or a class derived from std::bad_cast).
A pointer to a const object can be converted to a pointer to non-const object using the const_cast
keyword. Here we use const_cast to call a function that is not const-correct. It only accepts a non-
const char* argument even though it never writes through the pointer:
void bad_strlen(char*);
const char* s = "hello, world!";
bad_strlen(s); // compile error
bad_strlen(const_cast<char*>(s)); // OK, but it's better to make bad_strlen accept const char*
const_cast to reference type can be used to convert a const-qualified lvalue into a non-const-
qualified value.
const_cast is dangerous because it makes it impossible for the C++ type system to prevent you
from trying to modify a const object. Doing so results in undefined behavior.
A pointer (resp. reference) to an object type can be converted to a pointer (resp. reference) to any
other object type using reinterpret_cast. This does not call any constructors or conversion
functions.
int x = 42;
char* p = static_cast<char*>(&x); // error: static_cast cannot perform this conversion
char* p = reinterpret_cast<char*>(&x); // OK
*p = 'z'; // maybe this modifies x (see below)
C++11
The result of reinterpret_cast represents the same address as the operand, provided that the
address is appropriately aligned for the destination type. Otherwise, the result is unspecified.
int x = 42;
char& r = reinterpret_cast<char&>(x);
https://riptutorial.com/ 226
const void* px = &x;
const void* pr = &r;
assert(px == pr); // should never fire
C++11
The result of reinterpret_cast is unspecified, except that a pointer (resp. reference) will survive a
round trip from the source type to the destination type and back, as long as the destination type's
alignment requirement is not stricter than that of the source type.
int x = 123;
unsigned int& r1 = reinterpret_cast<unsigned int&>(x);
int& r2 = reinterpret_cast<int&>(r1);
r2 = 456; // sets x to 456
On most implementations, reinterpret_cast does not change the address, but this requirement
was not standardized until C++11.
An object pointer (including void*) or function pointer can be converted to an integer type using
reinterpret_cast. This will only compile if the destination type is long enough. The result is
implementation-defined and typically yields the numeric address of the byte in memory that the
pointer pointers to.
Typically, long or unsigned long is long enough to hold any pointer value, but this is not guaranteed
by the standard.
C++11
If the types std::intptr_t and std::uintptr_t exist, they are guaranteed to be long enough to hold
a void* (and hence any pointer to object type). However, they are not guaranteed to be long
enough to hold a function pointer.
Similarly, reinterpret_cast can be used to convert an integer type into a pointer type. Again the
result is implementation-defined, but a pointer value is guaranteed to be unchanged by a round
trip through an integer type. The standard does not guarantee that the value zero is converted to a
null pointer.
https://riptutorial.com/ 227
long x;
std::cin >> x;
register_callback(my_callback,
reinterpret_cast<void*>(x)); // hopefully this doesn't lose information...
A conversion that involves calling an explicit constructor or conversion function can't be done
implicitly. We can request that the conversion be done explicitly using static_cast. The meaning is
the same as that of a direct initialization, except that the result is a temporary.
class C {
std::unique_ptr<int> p;
public:
explicit C(int* p) : p(p) {}
};
void f(C c);
void g(int* p) {
f(p); // error: C::C(int*) is explicit
f(static_cast<C>(p)); // ok
f(C(p)); // equivalent to previous line
C c(p); f(c); // error: C is not copyable
}
Implicit conversion
static_cast can perform any implicit conversion. This use of static_cast can occasionally be
useful, such as in the following examples:
• When passing arguments to an ellipsis, the "expected" argument type is not statically known,
so no implicit conversion will occur.
Without the explicit type conversion, a double object would be passed to the ellipsis, and
undefined behaviour would occur.
• A derived class assignment operator can call a base class assignment operator like so:
https://riptutorial.com/ 228
Enum conversions
static_castcan convert from an integer or floating point type to an enumeration type (whether
scoped or unscoped), and vice versa. It can also convert between enumeration types.
C++11
○ If the enum's value can be represented exactly in the destination type, the result is that
value.
○ Otherwise, if the destination type is an integer type, the result is unspecified.
○ Otherwise, if the destination type is a floating point type, the result is the same as that
of converting to the underlying type and then to the floating point type.
Example:
○ If the original value is within the destination enum's range, the result is that value. Note
that this value might be unequal to all enumerators.
○ Otherwise, the result is unspecified (<= C++14) or undefined (>= C++17).
Example:
enum Scale {
SINGLE = 1,
DOUBLE = 2,
QUAD = 4
};
Scale s1 = 1; // error
Scale s2 = static_cast<Scale>(2); // s2 is DOUBLE
Scale s3 = static_cast<Scale>(3); // s3 has value 3, and is not equal to any enumerator
Scale s9 = static_cast<Scale>(9); // unspecified value in C++14; UB in C++17
C++11
• When a floating point type is converted to an enumeration type, the result is the same as
https://riptutorial.com/ 229
converting to the enum's underlying type and then to the enum type.
enum Direction {
UP = 0,
LEFT = 1,
DOWN = 2,
RIGHT = 3,
};
Direction d = static_cast<Direction>(3.14); // d is RIGHT
A pointer to member of derived class can be converted to a pointer to member of base class using
static_cast. The types pointed to must match.
If the operand is a null pointer to member value, the result is also a null pointer to member value.
Otherwise, the conversion is only valid if the member pointed to by the operand actually exists in
the destination class, or if the destination class is a base or derived class of the class containing
the member pointed to by the operand. static_cast does not check for validity. If the conversion is
not valid, the behaviour is undefined.
struct A {};
struct B { int x; };
struct C : A, B { int y; double z; };
int B::*p1 = &B::x;
int C::*p2 = p1; // ok; implicit conversion
int B::*p3 = p2; // error
int B::*p4 = static_cast<int B::*>(p2); // ok; p4 is equal to p1
int A::*p5 = static_cast<int A::*>(p2); // undefined; p2 points to x, which is a member
// of the unrelated class B
double C::*p6 = &C::z;
double A::*p7 = static_cast<double A::*>(p6); // ok, even though A doesn't contain z
int A::*p8 = static_cast<int A::*>(p6); // error: types don't match
void* to T*
In C++, void* cannot be implicitly converted to T* where T is an object type. Instead, static_cast
should be used to perform the conversion explicitly. If the operand actually points to a T object, the
result points to that object. Otherwise, the result is unspecified.
C++11
Even if the operand does not point to a T object, as long as the operand points to a byte whose
address is properly aligned for the type T, the result of the conversion points to the same byte.
https://riptutorial.com/ 230
const void* p1 = &c;
const char* p2 = p1; // error
const char* p3 = static_cast<const char*>(p1); // ok; p3 points to c
const int* p4 = static_cast<const int*>(p1); // unspecified in C++03;
// possibly unspecified in C++11 if
// alignof(int) > alignof(char)
char* p5 = static_cast<char*>(p1); // error: casting away constness
C-style casting
C-Style casting can be considered 'Best effort' casting and is named so as it is the only cast which
could be used in C. The syntax for this cast is (NewType)variable.
Whenever this cast is used, it uses one of the following c++ casts (in order):
• const_cast<NewType>(variable)
• static_cast<NewType>(variable)
• const_cast<NewType>(static_cast<const NewType>(variable))
• reinterpret_cast<const NewType>(variable)
• const_cast<NewType>(reinterpret_cast<const NewType>(variable))
Functional casting is very similar, though as a few restrictions as the result of its syntax:
NewType(expression). As a result, only types without spaces can be cast to.
It's better to use new c++ cast, because s more readable and can be spotted easily anywhere
inside a C++ source code and errors will be detected in compile-time, instead in run-time.
https://riptutorial.com/ 231
Chapter 42: Expression templates
Examples
Basic expression templates on element-wise algebraic expressions
Expression templates (denoted as ETs in the following) are a powerful template meta-
programming technique, used to speed-up calculations of sometimes quite expensive
expressions. It is widely used in different domains, for example in implementation of linear algebra
libraries.
For this example, consider the context of linear algebraic computations. More specifically,
computations involving only element-wise operations. This kind of computations are the most
basic applications of ETs, and they serve as a good introduction to how ETs work internally.
Here for the sake of simplicity, I'll assume that the class Vector and operation + (vector plus:
element-wise plus operation) and operation * (here means vector inner product: also element-wise
operation) are both correctly implemented, as how they should be, mathematically.
In a conventional implementation without using ETs (or other similar techniques), at least five
constructions of Vector instances take place in order to obtain the final result:
Implementation using ETs can eliminate the creation of temporary Vector _tmp in 2, thus leaving
only four constructions of Vector instances. More interestingly, consider the following expression
which is more complex:
There will also be four constructions of Vector instances in total: vec_1, vec_2, vec_3 and result. In
other words, in this example, where only element-wise operations are involved, it is
https://riptutorial.com/ 232
guaranteed that no temporary objects will be created from intermediate calculations.
Basically speaking, ETs for any algebraic computations consist of two building blocks:
So, specifically how do we implement ETs in this example? Let's walk through it now.
The expression to compute result can be decomposed further into two sub-expressions:
• Instead of compute right away each sub-expression, ETs first model the whole expression
using a graphical structure. Each node in the graph represents a PAE. The edge connection
of the nodes represent the actual computation flow. So for the above expression, we obtain
the following graph:
• The final computation is implemented by looking through the graph hierarchy: since here
https://riptutorial.com/ 233
we are dealing with only element-wise operations, the computation of each indexed value
in result can be done independently: the final evaluation of result can be lazily postponed
to a element-wise evaluation of each element of result. In other words, since the
computation of an element of result, elem_res, can be expressed using corresponding
elements in vec_1 (elem_1), vec_2 (elem_2) and vec_3 (elem_3) as:
there is therefore no need to create a temporary Vector to store the result of intermediate inner
product: the whole computation for one element can be done altogether, and be encoded
inside the indexed-access operation.
#ifndef EXPR_VEC
# define EXPR_VEC
# include <vector>
# include <cassert>
# include <utility>
# include <iostream>
# include <algorithm>
# include <functional>
///
/// This is a wrapper for std::vector. It's only purpose is to print out a log when a
/// vector constructions in called.
/// It wraps the indexed access operator [] and the size() method, which are
/// important for later ETs implementation.
///
// std::vector wrapper.
template<typename ScalarType> class Vector
{
public:
explicit Vector() { std::cout << "ctor called.\n"; };
explicit Vector(int size): _vec(size) { std::cout << "ctor called.\n"; };
explicit Vector(const std::vector<ScalarType> &vec): _vec(vec)
{ std::cout << "ctor called.\n"; };
https://riptutorial.com/ 234
decltype(auto) operator[](int indx) { return _vec[indx]; }
decltype(auto) operator[](int indx) const { return _vec[indx]; }
private:
std::vector<ScalarType> _vec;
};
///
/// These are conventional overloads of operator + (the vector plus operation)
/// and operator * (the vector inner product operation) without using the expression
/// templates. They are later used for bench-marking purpose.
///
std::vector<ScalarType> _vec;
_vec.resize(lhs().size());
std::transform(std::cbegin(lhs()), std::cend(lhs()),
std::cbegin(rhs()), std::begin(_vec),
std::plus<>());
return Vector<ScalarType>(std::move(_vec));
}
std::vector<ScalarType> _vec;
_vec.resize(lhs().size());
std::transform(std::cbegin(lhs()), std::cend(lhs()),
std::cbegin(rhs()), std::begin(_vec),
std::multiplies<>());
return Vector<ScalarType>(std::move(_vec));
}
#endif //!EXPR_VEC
https://riptutorial.com/ 235
Let's break it down to sections.
1. Section 1 implements a base class for all expressions. It employs the Curiously Recurring
Template Pattern (CRTP).
2. Section 2 implements the first PAE: a terminal, which is just a wrapper (const reference) of
an input data structure containing real input value for computation.
3. Section 3 implements the second PAE: binary_operation, which is a class template later
used for vector_plus and vector_innerprod. It's parametrized by the type of operation, the
left-hand-side PAE and the right-hand-side PAE. The actual computation is encoded in
the indexed-access operator.
4. Section 4 defines vector_plus and vector_innerprod operations as element-wise operation.
It also overload operator + and * for PAEs: such that these two operations also return PAE.
#ifndef EXPR_EXPR
# define EXPR_EXPR
namespace expr
{
/// -----------------------------------------
///
/// Section 1.
///
/// The first section is a base class template for all kinds of expression. It
/// employs the Curiously Recurring Template Pattern, which enables its instantiation
/// to any kind of expression structure inheriting from it.
///
/// -----------------------------------------
protected:
explicit expr_base() {};
int size() const { return self().size_impl(); }
auto operator[](int indx) const { return self().at_impl(indx); }
auto operator()() const { return self()(); };
};
/// -----------------------------------------
///
/// The following section 2 & 3 are abstractions of pure algebraic expressions (PAE).
/// Any PAE can be converted to a real object instance using operator(): it is in
/// this conversion process, where the real computations are done.
///
https://riptutorial.com/ 236
/// Section 2. Terminal
///
/// A terminal is an abstraction wrapping a const reference to the Vector data
/// structure. It inherits from expr_base, therefore providing a unified interface
/// wrapping a Vector into a PAE.
///
/// It provides the size() method, indexed access through at_impl() and a conversion
/// to referenced object through () operator.
///
/// It might no be necessary for user defined data structures to have a terminal
/// wrapper, since user defined structure can inherit expr_base, therefore eliminates
/// the need to provide such terminal wrapper.
///
/// -----------------------------------------
private:
const DataType &_val;
};
/// -----------------------------------------
///
/// Section 3. Binary operation expression.
///
/// This is a PAE abstraction of any binary expression. Similarly it inherits from
/// expr_base.
///
/// It provides the size() method, indexed access through at_impl() and a conversion
/// to referenced object through () operator. Each call to the at_impl() method is
/// a element wise computation.
///
/// -----------------------------------------
explicit binary_ops(const Ops &ops, const lExpr &lxpr, const rExpr &rxpr)
: _ops(ops), _lxpr(lxpr), _rxpr(rxpr) {};
https://riptutorial.com/ 237
int size_impl() const { return _lxpr.size(); };
/// -----------------------------------------
/// Section 4.
///
/// The following two structs defines algebraic operations on PAEs: here only vector
/// plus and vector inner product are implemented.
///
/// First, some element-wise operations are defined : in other words, vec_plus and
/// vec_prod acts on elements in Vectors, but not whole Vectors.
///
/// Then, operator + & * are overloaded on PAEs, such that: + & * operations on PAEs
/// also return PAEs.
///
/// -----------------------------------------
https://riptutorial.com/ 238
auto operator+(const lExpr &lhs, const rExpr &rhs)
{ return binary_ops<vec_plus_t,lExpr,rExpr>(vec_plus,lhs,rhs); }
} //!expr
#endif //!EXPR_EXPR
# include <chrono>
# include <iomanip>
# include <iostream>
# include "vec.hh"
# include "expr.hh"
# include "boost/core/demangle.hpp"
int main()
{
using dtype = float;
constexpr int size = 5e7;
std::vector<dtype> _vec1(size);
std::vector<dtype> _vec2(size);
std::vector<dtype> _vec3(size);
Vector<dtype> vec1(std::move(_vec1));
Vector<dtype> vec2(std::move(_vec2));
Vector<dtype> vec3(std::move(_vec3));
https://riptutorial.com/ 239
expr::terminal<Vector<dtype>> vec4(vec1);
expr::terminal<Vector<dtype>> vec5(vec2);
expr::terminal<Vector<dtype>> vec6(vec3);
return 0;
}
Here's one possible output when compiled with -O3 -std=c++14 using GCC 5.3:
ctor called.
ctor called.
ctor called.
• Using ETs achieves rather significant performance boost in this case ( > 3x).
• Creation of temporary Vector object is eliminated. As in the ETs case, ctor is called only
once.
• Boost::demangle was used to visualize the type of ETs return before conversion: it clearly
constructed exactly the same expression graph demonstrated above.
• An obvious disadvantage of ETs is the learning curve, the complexity of implementation and
code-maintenance difficulty. In the above example where only element-wise operations are
considered, the implementation contains already enormous amount of boilerplates, let alone
https://riptutorial.com/ 240
in real world, where more complex algebraic expressions occur in every computation and
element-wise independence no longer hold (for example matrix multiplication), the difficulty
will be exponential.
• Another caveat of using ETs is that they do play well with the auto keyword. As mentioned
above, PAEs are essentially proxies: and proxies basically do not play well with auto.
Consider the following example:
Here in each iteration of the for loop, result will be re-evaluated, since the expression graph
instead of the computed value is passed to the for loop.
• boost::proto is a powerful library letting you define your own rules & grammars for your own
expressions and execute using ETs.
• Eigen is a library for linear algebra that implements various algebraic computations
efficiently using ETs.
Before actually diving into expression templates, you should understand why you need them in the
first place. To illustrate this, consider the very simple Matrix class given below:
https://riptutorial.com/ 241
private:
std::vector<T> values;
};
Given the previous class definition, you can now write Matrix expressions such as:
// initialize a, b & c
for (std::size_t y = 0; y != rows; ++y) {
for (std::size_t x = 0; x != cols; ++x) {
a(x, y) = 1.0;
b(x, y) = 2.0;
c(x, y) = 3.0;
}
}
As illustrated above, being able to overload operator+() provides you with a notation which mimics
the natural mathematical notation for matrices.
To understand why, you have to consider what happens when you write an expression such as
Matrix d = a + b + c. This in fact expands to ((a + b) + c) or operator+(operator+(a, b), c). In
other words, the loop inside operator+() is executed twice, whereas it could have been easily
performed in a single pass. This also results in 2 temporaries being created, which further
degrades performance. In essence, by adding the flexibility to use a notation close to its
mathematical counterpart, you have also made the Matrix class highly inefficient.
For example, without operator overloading, you could implement a far more efficient Matrix
summation using a single pass:
https://riptutorial.com/ 242
const Matrix<T, COL, ROW>& c)
{
Matrix<T, COL, ROW> result;
for (size_t y = 0; y != ROW; ++y) {
for (size_t x = 0; x != COL; ++x) {
result(x, y) = a(x, y) + b(x, y) + c(x, y);
}
}
return result;
}
The previous example however has its own disadvantages because it creates a far more
convoluted interface for the Matrix class (you would have to consider methods such as
Matrix::add2(), Matrix::AddMultiply() and so on).
Instead let us take a step back and see how we can adapt operator overloading to perform in a
more efficient way
The problem stems from the fact that the expression Matrix d = a + b + c is evaluated too
"eagerly" before you have had an opportunity to build the entire expression tree. In other words,
what you really want to achieve is to evaluate a + b + c in one pass and only once you actually
need to assign the resulting expressing to d.
This is the core idea behind expression templates: instead of having operator+() evaluate
immediately the result of adding two Matrix instances, it will return an "expression template" for
future evaluation once the entire expression tree has been built.
For example, here is a possible implementation for an expression template corresponding to the
summation of 2 types:
As you can see, operator+() no longer returns an "eager evaluation" of the result of adding 2
https://riptutorial.com/ 243
Matrix instances (which would be another Matrix instance), but instead an expression template
representing the addition operation. The most important point to keep in mind is that the
expression has not been evaluated yet. It merely holds references to its operands.
In fact, nothing stops you from instantiating the MatrixSum<> expression template as follows:
You can however at a later stage, when you actually need the result of the summation, evaluate
the expression d = a + b as follows:
As you can see, another benefit of using an expression template, is that you have basically
managed to evaluate the sum of a and b and assign it to d in a single pass.
Also, nothing stops you from combining multiple expression templates. For example, a + b + c
would result in the following expression template:
And here again you can evaluate the final result using a single pass:
Finally, the last piece of the puzzle is to actually plug your expression template into the Matrix
class. This is essentially achieved by providing an implementation for Matrix::operator=(), which
takes the expression template as an argument and evaluates it in one pass, as you did "manually"
before:
https://riptutorial.com/ 244
Matrix<T, COL, ROW>& operator=(const E& expression) {
for (std::size_t y = 0; y != rows(); ++y) {
for (std::size_t x = 0; x != cols(); ++x) {
values[y * COL + x] = expression(x, y);
}
}
return *this;
}
private:
std::vector<T> values;
};
https://riptutorial.com/ 245
Chapter 43: File I/O
Introduction
C++ file I/O is done via streams. The key abstractions are:
Streams use std::locale, e.g., for details of the formatting and for translation between external
encodings and the internal encoding.
Examples
Opening a file
Opening a file is done in the same way for all 3 file streams (ifstream, ofstream, and fstream).
std::fstream iofs("foo.txt"); // fstream: Opens file "foo.txt" for reading and writing.
Alternatively, you can use the file stream's member function open():
std::ifstream ifs;
ifs.open("bar.txt"); // ifstream: Opens file "bar.txt" for reading only.
std::ofstream ofs;
ofs.open("bar.txt"); // ofstream: Opens file "bar.txt" for writing only.
std::fstream iofs;
iofs.open("bar.txt"); // fstream: Opens file "bar.txt" for reading and writing.
You should always check if a file has been opened successfully (even when writing). Failures can
include: the file doesn't exist, file hasn't the right access rights, file is already in use, disk errors
occurred, drive disconnected ... Checking can be done as follows:
https://riptutorial.com/ 246
// Try to read the file 'foo.txt'.
std::ifstream ifs("fooo.txt"); // Note the typo; the file can't be opened.
When file path contains backslashes (for example, on Windows system) you should properly
escape them:
C++11
C++11
If you want to open file with non-ASCII characters in path on Windows currently you can use non-
standard wide character path argument:
If you know how the data is formatted, you can use the stream extraction operator (>>). Let's
assume you have a file named foo.txt which contains the following data:
Then you can use the following code to read that data from the file:
// Define variables.
std::ifstream is("foo.txt");
std::string firstname, lastname;
int age, bmonth, bday, byear;
https://riptutorial.com/ 247
// Extract firstname, lastname, age, bday month, bday day, and bday year in that order.
// Note: '>>' returns false if it reached EOF (end of file) or if the input data doesn't
// correspond to the type of the input variable (for example, the string "foo" can't be
// extracted into an 'int' variable).
while (is >> firstname >> lastname >> age >> bmonth >> bday >> byear)
// Process the data that has been read.
The stream extraction operator >> extracts every character and stops if it finds a character that
can't be stored or if it is a special character:
This means that the following version of the file foo.txt will also be successfully read by the
previous code:
John
Doe 25
4 6 1987
Jane
Doe
15 5
24
1976
The stream extraction operator >> always returns the stream given to it. Therefore, multiple
operators can be chained together in order to read data consecutively. However, a stream can
also be used as a Boolean expression (as shown in the while loop in the previous code). This is
because the stream classes have a conversion operator for the type bool. This bool() operator will
return true as long as the stream has no errors. If a stream goes into an error state (for example,
because no more data can be extracted), then the bool() operator will return false. Therefore, the
while loop in the previous code will be exited after the input file has been read to its end.
If you wish to read an entire file as a string, you may use the following code:
// Opens 'foo.txt'.
std::ifstream is("foo.txt");
std::string whole_file;
https://riptutorial.com/ 248
This code reserves space for the string in order to cut down on unneeded memory allocations.
If you want to read a file line by line, you can use the function getline():
std::ifstream is("foo.txt");
If you want to read a fixed number of characters, you can use the stream's member function read()
:
std::ifstream is("foo.txt");
char str[4];
After executing a read command, you should always check if the error state flag failbit has been
set, as it indicates whether the operation failed or not. This can be done by calling the file stream's
member function fail():
if (is.fail())
// Failed to read!
Writing to a file
There are several ways to write to a file. The easiest way is to use an output file stream (ofstream)
together with the stream insertion operator (<<):
std::ofstream os("foo.txt");
if(os.is_open()){
os << "Hello World!";
}
Instead of <<, you can also use the output file stream's member function write():
std::ofstream os("foo.txt");
if(os.is_open()){
char data[] = "Foo";
After writing to a stream, you should always check if error state flag badbit has been set, as it
indicates whether the operation failed or not. This can be done by calling the output file stream's
member function bad():
https://riptutorial.com/ 249
os << "Hello Badbit!"; // This operation might fail for any reason.
if (os.bad())
// Failed to write!
Opening modes
When creating a file stream, you can specify an opening mode. An opening mode is basically a
setting to control how the stream opens the file.
An opening mode can be provided as second parameter to the constructor of a file stream or to its
open() member function:
std::ifstream is;
is.open("foo.txt", std::ios::in | std::ios::binary);
It is to be noted that you have to set ios::in or ios::out if you want to set other flags as they are
not implicitly set by the iostream members although they have a correct default value.
If you don't specify an opening mode, then the following default modes are used:
• ifstream - in
• ofstream - out
• fstream - in and out
The file opening modes that you may specify by design are:
ate at end Input Goes to the end of the file when opening.
Note: Setting the binary mode lets the data be read/written exactly as-is; not setting it enables the
translation of the newline '\n' character to/from a platform specific end of line sequence.
https://riptutorial.com/ 250
Closing a file
Explicitly closing a file is rarely necessary in C++, as a file stream will automatically close its
associated file in its destructor. However, you should try to limit the lifetime of a file stream object,
so that it does not keep the file handle open longer than necessary. For example, this can be done
by putting all file operations into an own scope ({}):
// Write data.
output << prepared_data;
} // The ofstream will go out of scope here.
// Its destructor will take care of closing the file properly.
Calling close() explicitly is only necessary if you want to reuse the same fstream object later, but
don't want to keep the file open in between:
// Preparing data might take a long time. Therefore, we don't open the output file stream
// before we actually can write some data to it.
std::string const more_prepared_data = prepare_complex_data();
// Open the file "foo.txt" for the second time once we are ready for writing.
output.open("foo.txt");
Flushing a stream
File streams are buffered by default, as are many other types of streams. This means that writes
to the stream may not cause the underlying file to change immediately. In oder to force all buffered
writes to take place immediately, you can flush the stream. You can do this either directly by
invoking the flush() method or through the std::flush stream manipulator:
std::ofstream os("foo.txt");
os << "Hello World!" << std::flush;
https://riptutorial.com/ 251
char data[3] = "Foo";
os.write(data, 3);
os.flush();
There is a stream manipulator std::endl that combines writing a newline with flushing the stream:
Buffering can improve the performance of writing to a stream. Therefore, applications that do a lot
of writing should avoid flushing unnecessarily. Contrary, if I/O is done infrequently, applications
should consider flushing frequently in order to avoid data getting stuck in the stream object.
std::ifstream f("file.txt");
if (f)
{
std::stringstream buffer;
buffer << f.rdbuf();
f.close();
The rdbuf() method returns a pointer to a streambuf that can be pushed into buffer via the
stringstream::operator<< member function.
std::ifstream f("file.txt");
if (f)
{
std::string str((std::istreambuf_iterator<char>(f)),
std::istreambuf_iterator<char>());
// Operations on `str`...
}
This is nice because requires little code (and allows reading a file directly into any STL container,
not only strings) but can be slow for big files.
NOTE: the extra parentheses around the first argument to the string constructor are essential to
prevent the most vexing parse problem.
https://riptutorial.com/ 252
std::ifstream f("file.txt");
if (f)
{
f.seekg(0, std::ios::end);
const auto size = f.tellg();
// Operations on `str`...
}
In the example below we use std::string and operator>> to read items from the file.
std::ifstream file("file3.txt");
std::vector<std::string> v;
std::string s;
while(file >> s) // keep reading until we run out
{
v.push_back(s);
}
In the above example we are simply iterating through the file reading one "item" at a time using
operator>>. This same affect can be achieved using the std::istream_iterator which is an input
iterator that reads one "item" at a time from the stream. Also most containers can be constructed
using two iterators so we can simplify the above code to:
std::ifstream file("file3.txt");
std::vector<std::string> v(std::istream_iterator<std::string>{file},
std::istream_iterator<std::string>{});
We can extend this to read any object types we like by simply specifying the object we want to
read as the template parameter to the std::istream_iterator. Thus we can simply extend the
above to read lines (rather than words) like this:
https://riptutorial.com/ 253
// Read a line from a stream.
friend std::istream& operator>>(std::istream& stream, Line& line)
{
return std::getline(stream, line.data);
}
};
std::ifstream file("file3.txt");
C++11
struct info_type
{
std::string name;
int age;
float height;
void func4()
{
auto file = std::ifstream("file4.txt");
std::vector<info_type> v;
for(info_type info; file >> info;) // keep reading until we run out
{
// we only get here if the read succeeded
v.push_back(info);
}
file4.txt
https://riptutorial.com/ 254
Wogger Wabbit
2
6.2
Bilbo Baggins
111
81.3
Mary Poppins
29
154.8
Output:
Copying a file
C++17
With C++17 the standard way to copy a file is including the <filesystem> header and using
copy_file:
std::fileystem::copy_file("source_filename", "dest_filename");
The filesystem library was originally developed as boost.filesystem and finally merged to ISO C++
as of C++17.
eof returns true only after reading the end of file. It does NOT indicate that the next read will be
the end of stream.
while (!f.eof())
{
// Everything is OK
f >> buffer;
https://riptutorial.com/ 255
/* Use `buffer` */
}
while (!f.eof())
{
f >> buffer >> std::ws;
if (f.fail())
break;
/* Use `buffer` */
}
but
Further references:
If you need to write a file using different locale settings to the default, you can use std::locale and
std::basic_ios::imbue() to do that for a specific file stream:
• You should always apply a local to a stream before opening the file.
• Once the stream has been imbued you should not change the locale.
Reasons for Restrictions: Imbuing a file stream with a locale has undefined behavior if the
current locale is not state independent or not pointing at the beginning of the file.
UTF-8 streams (and others) are not state independent. Also a file stream with a UTF-8 locale may
try and read the BOM marker from the file when it is opened; so just opening the file may read
characters from the file and it will not be at the beginning.
#include <iostream>
#include <fstream>
#include <locale>
int main()
{
https://riptutorial.com/ 256
std::cout << "User-preferred locale setting is "
<< std::locale("").name().c_str() << std::endl;
Explicitly switching to the classic "C" locale is useful if your program uses a different default locale
and you want to ensure a fixed standard for reading and writing files. With a "C" preferred locale,
the example writes
78,123.456
78,123.456
78123.456
If, for example, the preferred locale is German and hence uses a different number format, the
example writes
78 123,456
78,123.456
78123.456
https://riptutorial.com/ 257
Chapter 44: Floating Point Arithmetic
Examples
Floating Point Numbers are Weird
The first mistake that nearly every single programmer makes is presuming that this code will work
as intended:
float total = 0;
for(float a = 0; a != 2; a += 0.01f) {
total += a;
}
The novice programmer assumes that this will sum up every single number in the range 0, 0.01,
0.02, 0.03, ..., 1.97, 1.98, 1.99, to yield the result 199—the mathematically correct answer.
1. The program as written never concludes. a never becomes equal to 2, and the loop never
terminates.
2. If we rewrite the loop logic to check a < 2 instead, the loop terminates, but the total ends up
being something different from 199. On IEEE754-compliant machines, it will often sum up to
about 201 instead.
The reason that this happens is that Floating Point Numbers represent Approximations of
their assigned values.
double a = 0.1;
double b = 0.2;
double c = 0.3;
if(a + b == c)
//This never prints on IEEE754-compliant machines
std::cout << "This Computer is Magic!" << std::endl;
else
std::cout << "This Computer is pretty normal, all things considered." << std::endl;
Though what we the programmer see is three numbers written in base10, what the compiler (and
the underlying hardware) see are binary numbers. Because 0.1, 0.2, and 0.3 require perfect
division by 10—which is quite easy in a base-10 system, but impossible in a base-2 system—these
numbers have to be stored in imprecise formats, similar to how the number 1/3 has to be stored in
the imprecise form 0.333333333333333... in base-10.
https://riptutorial.com/ 258
representation of 0.2
double c = 0011111111010011001100110011001100110011001100110011001100110011; //imperfect
representation of 0.3
double a + b = 0011111111010011001100110011001100110011001100110011001100110100; //Note that
this is not quite equal to the "canonical" 0.3!
https://riptutorial.com/ 259
Chapter 45: Flow Control
Remarks
Check out the loops topic for the different kind of loops.
Examples
case
Introduces a case label of a switch statement. The operand must be a constant expression and
match the switch condition in type. When the switch statement is executed, it will jump to the case
label with operand equal to the condition, if any.
char c = getchar();
bool confirmed;
switch (c) {
case 'y':
confirmed = true;
break;
case 'n':
confirmed = false;
break;
default:
std::cout << "invalid response!\n";
abort();
}
switch
The keyword switch is followed by a parenthesized condition and a block, which may contain case
labels and an optional default label. When the switch statement is executed, control will be
transferred either to a case label with a value matching that of the condition, if any, or to the default
label, if any.
The condition must be an expression or a declaration, which has either integer or enumeration
type, or a class type with a conversion function to integer or enumeration type.
char c = getchar();
bool confirmed;
switch (c) {
case 'y':
confirmed = true;
break;
https://riptutorial.com/ 260
case 'n':
confirmed = false;
break;
default:
std::cout << "invalid response!\n";
abort();
}
catch
The catch keyword introduces an exception handler, that is, a block into which control will be
transferred when an exception of compatible type is thrown. The catch keyword is followed by a
parenthesized exception declaration, which is similar in form to a function parameter declaration:
the parameter name may be omitted, and the ellipsis ... is allowed, which matches any type. The
exception handler will only handle the exception if its declaration is compatible with the type of the
exception. For more details, see catching exceptions.
try {
std::vector<int> v(N);
// do something
} catch (const std::bad_alloc&) {
std::cout << "failed to allocate memory for vector!" << std::endl;
} catch (const std::runtime_error& e) {
std::cout << "runtime error: " << e.what() << std::endl;
} catch (...) {
std::cout << "unexpected exception!" << std::endl;
throw;
}
default
In a switch statement, introduces a label that will be jumped to if the condition's value is not equal
to any of the case labels' values.
char c = getchar();
bool confirmed;
switch (c) {
case 'y':
confirmed = true;
break;
case 'n':
confirmed = false;
break;
default:
std::cout << "invalid response!\n";
abort();
}
C++11
Defines a default constructor, copy constructor, move constructor, destructor, copy assignment
operator, or move assignment operator to have its default behaviour.
https://riptutorial.com/ 261
class Base {
// ...
// we want to be able to delete derived classes through Base*,
// but have the usual behaviour for Base's destructor.
virtual ~Base() = default;
};
if
int x;
std::cout << "Please enter a positive number." << std::endl;
std::cin >> x;
if (x <= 0) {
std::cout << "You didn't enter a positive number!" << std::endl;
abort();
}
else
The first substatement of an if statement may be followed by the keyword else. The substatement
after the else keyword will be executed when the condition is falsey (that is, when the first
substatement is not executed).
int x;
std::cin >> x;
if (x%2 == 0) {
std::cout << "The number is even\n";
} else {
std::cout << "The number is odd\n";
}
goto
https://riptutorial.com/ 262
return
If return has an operand, the operand is converted to the function's return type, and the converted
value is returned to the caller.
int f() {
return 42;
}
int x = f(); // x is 42
int g() {
return 3.14;
}
int y = g(); // y is 3
If return does not have an operand, the function must have void return type. As a special case, a
void-returning function can also return an expression if the expression has type void.
void f(int x) {
if (x < 0) return;
std::cout << sqrt(x);
}
int g() { return 42; }
void h() {
return f(); // calls f, then returns
return g(); // ill-formed
}
When main returns, std::exit is implicitly called with the return value, and the value is thus
returned to the execution environment. (However, returning from main destroys automatic local
variables, while calling std::exit directly does not.)
throw
1. When throw occurs in an expression with an operand, its effect is to throw an exception,
which is a copy of the operand.
https://riptutorial.com/ 263
2. When throw occurs in an expression without an operand, its effect is to rethrow the current
exception. If there is no current exception, std::terminate is called.
try {
// something risky
} catch (const std::bad_alloc&) {
std::cerr << "out of memory" << std::endl;
} catch (...) {
std::cerr << "unexpected exception" << std::endl;
// hope the caller knows how to handle this exception
throw;
}
Note that the first two uses of throw listed above constitute expressions rather than statements.
(The type of a throw expression is void.) This makes it possible to nest them within expressions,
like so:
try
The keyword try is followed by a block, or by a constructor initializer list and then a block (see
here). The try block is followed by one or more catch blocks. If an exception propagates out of the
try block, each of the corresponding catch blocks after the try block has the opportunity to handle
the exception, if the types match.
if and else:
https://riptutorial.com/ 264
it used to check whether the given expression returns true or false and acts as such:
if (condition) statement
the condition can be any valid C++ expression that returns something that be checked against
truth/falsehood for example:
if (true) { /* code here */ } // evaluate that true is true and execute the code in the
brackets
if (false) { /* code here */ } // always skip the code since false is always false
if(istrue()) { } // evaluate the function, if it returns true, the if will execute the code
if(isTrue(var)) { } //evalute the return of the function after passing the argument var
if(a == b) { } // this will evaluate the return of the experssion (a==b) which will be true if
equal and false if unequal
if(a) { } //if a is a boolean type, it will evaluate for its value, if it's an integer, any
non zero value will be true,
if (a && b) { } // will be true only if both a and b are true (binary operators are outside
the scope here
if (a || b ) { } //true if a or b is true
using if/ifelse/else:
if (a== "test") {
//will execute if a is a string "test"
} else {
// only if the first failed, will execute
}
if (a=='a') {
// if a is a char valued 'a'
} else if (a=='b') {
// if a is a char valued 'b'
} else if (a=='c') {
// if a is a char valued 'c'
} else {
//if a is none of the above
}
however it must be noted that you should use 'switch' instead if your code checks for the same
variable's value
https://riptutorial.com/ 265
Jump statements : break, continue, goto, exit.
Using break we can leave a loop even if the condition for its end is not fulfilled. It can be used to
end an infinite loop, or to force it to end before its natural end
The syntax is
break;
Example: we often use break in switch cases,ie once a case i switch is satisfied then the code
block of that condition is executed .
switch(conditon){
case 1: block1;
case 2: block2;
case 3: block3;
default: blockdefault;
}
in this case if case 1 is satisfied then block 1 is executed , what we really want is only the block1 to
be processed but instead once the block1 is processed remaining blocks,block2,block3 and
blockdefault are also processed even though only case 1 was satified.To avoid this we use break
at the end of each block like :
switch(condition){
case 1: block1;
break;
case 2: block2;
break;
case 3: block3;
break;
default: blockdefault;
break;
}
so only one block is processed and the control moves out of the switch loop.
break can also be used in other conditional and non conditional loops like if,while,for etc;
example:
if(condition1){
....
if(condition2){
.......
break;
}
...
}
https://riptutorial.com/ 266
The continue instruction:
The continue instruction causes the program to skip the rest of the loop in the present iteration as
if the end of the statement block would have been reached, causing it to jump to the following
iteration.
The syntax is
continue;
for(int i=0;i<10;i++){
if(i%2==0)
continue;
cout<<"\n @"<<i;
}
@1
@3
@5
@7
@9
i this code whenever the condition i%2==0 is satisfied continue is processed,this causes the
compiler to skip all the remaining code( printing @ and i) and increment/decrement statement of
the loop gets executed.
It allows making an absolute jump to another point in the program. You should use this feature
carefully since its execution ignores any type of nesting limitation. The destination point is
identified by a label, which is then used as an argument for the goto instruction. A label is made of
a valid identifier followed by a colon (:)
The syntax is
goto label;
..
https://riptutorial.com/ 267
.
label: statement;
Note: Use of goto statement is highly discouraged because it makes difficult to trace the control
flow of a program, making the program hard to understand and hard to modify.
Example :
int num = 1;
STEP:
do{
if( num%2==0 )
{
num = num + 1;
goto STEP;
}
output :
value of num : 1
value of num : 3
value of num : 5
value of num : 7
value of num : 9
whenever the condition num%2==0 is satisfied the goto sends the execution control to the beginning
of the do-while loop.
https://riptutorial.com/ 268
The exit function:
exitis a function defined in cstdlib. The purpose of exit is to terminate the running program with
an specific exit code. Its prototype is:
https://riptutorial.com/ 269
Chapter 46: Fold Expressions
Remarks
Fold Expressions are supported for the following operators
When folding over an empty sequence, a fold expression is ill-formed, except for the following
three operators:
&& true
|| false
, void()
Examples
Unary Folds
Unary folds are used to fold parameter packs over a specific operator. There are 2 kinds of unary
folds:
Here is an example
template<typename... Ts>
int sum(Ts... args)
{
https://riptutorial.com/ 270
return (... + args); //Unary left fold
//return (args + ...); //Unary right fold
Binary Folds
Here is an example:
template<typename... Ts>
int removeFrom(int num, Ts... args)
{
return (num - ... - args); //Binary left fold
// Note that a binary right fold cannot be used
// due to the lack of associativity of operator-
}
https://riptutorial.com/ 271
void print_all(std::ostream& os, Ts const&... args) {
(void(os << args), ...);
}
https://riptutorial.com/ 272
Chapter 47: Friend keyword
Introduction
Well-designed classes encapsulate their functionality, hiding their implementation while providing
a clean, documented interface. This allows redesign or change so long as the interface is
unchanged.
In a more complex scenario, multiple classes that rely on each others' implementation details may
be required. Friend classes and functions allow these peers access to each others' details, without
compromising the encapsulation and information hiding of the documented interface.
Examples
Friend function
A class or a structure may declare any function it's friend. If a function is a friend of a class, it may
access all it's protected and private members:
class PrivateHolder {
public:
PrivateHolder(int val) : private_value(val) {}
private:
int private_value;
// Declare one of the function as a friend.
friend void friend_function();
};
void non_friend_function() {
PrivateHolder ph(10);
// Compilation error: private_value is private.
std::cout << ph.private_value << std::endl;
}
void friend_function() {
// OK: friends may access private values.
PrivateHolder ph(10);
std::cout << ph.private_value << std::endl;
}
Access modifiers do not alter friend semantics. Public, protected and private declarations of a
friend are equivalent.
https://riptutorial.com/ 273
public:
PrivateHolderDerived(int val) : PrivateHolder(val) {}
private:
int derived_private_value = 0;
};
void friend_function() {
PrivateHolderDerived pd(20);
// OK.
std::cout << pd.private_value << std::endl;
// Compilation error: derived_private_value is private.
std::cout << pd.derived_private_value << std::endl;
}
Friend method
class Accesser {
public:
void private_accesser();
};
class PrivateHolder {
public:
PrivateHolder(int val) : private_value(val) {}
friend void Accesser::private_accesser();
private:
int private_value;
};
void Accesser::private_accesser() {
PrivateHolder ph(10);
// OK: this method is declares as friend.
std::cout << ph.private_value << std::endl;
}
Friend class
A whole class may be declared as friend. Friend class declaration means that any member of the
friend may access private and protected members of the declaring class:
class Accesser {
public:
void private_accesser1();
void private_accesser2();
};
class PrivateHolder {
https://riptutorial.com/ 274
public:
PrivateHolder(int val) : private_value(val) {}
friend class Accesser;
private:
int private_value;
};
void Accesser::private_accesser1() {
PrivateHolder ph(10);
// OK.
std::cout << ph.private_value << std::endl;
}
void Accesser::private_accesser2() {
PrivateHolder ph(10);
// OK.
std::cout << ph.private_value + 1 << std::endl;
}
Friend class declaration is not reflexive. If classes need private access in both directions, both of
them need friend declarations.
class Accesser {
public:
void private_accesser1();
void private_accesser2();
private:
int private_value = 0;
};
class PrivateHolder {
public:
PrivateHolder(int val) : private_value(val) {}
// Accesser is a friend of PrivateHolder
friend class Accesser;
void reverse_accesse() {
// but PrivateHolder cannot access Accesser's members.
Accesser a;
std::cout << a.private_value;
}
private:
int private_value;
};
https://riptutorial.com/ 275
Chapter 48: Function Overloading
Introduction
See also separate topic on Overload Resolution
Remarks
Ambiguities can occur when one type can be implicitly converted into more than one type and
there is no matching function for that specific type.
For example:
Examples
What is Function Overloading?
Function overloading is having multiple functions declared in the same scope with the exact same
name exist in the same place (known as scope) differing only in their signature, meaning the
arguments they accept.
Suppose you are writing a series of functions for generalized printing capabilities, beginning with
std::string:
This works fine, but suppose you want a function that also accepts an int and prints that too. You
could write:
But because the two functions accept different parameters, you can simply write:
https://riptutorial.com/ 276
{
std::cout << "This is an int: " << num << std::endl;
}
Now you have 2 functions, both named print, but with different signatures. One accepts
std::string, the other one an int. Now you can call them without worrying about different names:
Instead of:
print("Hello world!");
print_int(1337);
When you have overloaded functions, the compiler infers which of the functions to call from the
parameters you provide it. Care must be taken when writing function overloads. For example, with
implicit type conversions:
Now it's not immediately clear which overload of print is called when you write:
print(5);
And you might need to give your compiler some clues, like:
print(static_cast<double>(5));
print(static_cast<int>(5));
print(5.0);
Some care also needs to be taken when writing overloads that accept optional parameters:
// WRONG CODE
void print(int num1, int num2 = 0) //num2 defaults to 0 if not included
{
std::cout << "These are ints: << num1 << " and " << num2 << std::endl;
}
void print(int num)
{
std::cout << "This is an int: " << num << std::endl;
}
Because there's no way for the compiler to tell if a call like print(17) is meant for the first or
https://riptutorial.com/ 277
second function because of the optional second parameter, this will fail to compile.
Note that you cannot overload a function based on its return type. For example:
// WRONG CODE
std::string getValue()
{
return "hello";
}
int getValue()
{
return 0;
}
int x = getValue();
This will cause a compilation error as the compiler will not be able to work out which version of
getValue to call, even though the return type is assigned to an int.
Functions within a class can be overloaded for when they are accessed through a cv-qualified
reference to that class; this is most commonly used to overload for const, but can be used to
overload for volatile and const volatile, too. This is because all non-static member functions take
this as a hidden parameter, which the cv-qualifiers are applied to. This is most commonly used to
overload for const, but can also be used for volatile and const volatile.
This is necessary because a member function can only be called if it is at least as cv-qualified as
the instance it's called on. While a non-const instance can call both const and non-const members,
a const instance can only call const members. This allows a function to have different behaviour
depending on the calling instance's cv-qualifiers, and allows the programmer to disallow functions
for an undesired cv-qualifier(s) by not providing a version with that qualifier(s).
A class with some basic print method could be const overloaded like so:
#include <iostream>
class Integer
{
public:
Integer(int i_): i{i_}{}
void print()
{
std::cout << "int: " << i << std::endl;
}
https://riptutorial.com/ 278
}
protected:
int i;
};
int main()
{
Integer i{5};
const Integer &ic = i;
This is a key tenet of const correctness: By marking member functions as const, they are allowed
to be called on const instances, which in turn allows functions to take instances as const
pointers/references if they don't need to modify them. This allows code to specify whether it
modifies state by taking unmodified parameters as const and modified parameters without cv-
qualifiers, making code both safer and more readable.
class ConstCorrect
{
public:
void good_func() const
{
std::cout << "I care not whether the instance is const." << std::endl;
}
void bad_func()
{
std::cout << "I can only be called on non-const, non-volatile instances." <<
std::endl;
}
};
No class members can be modified within a const member function. If there is some member that
you really need to modify, such as locking a std::mutex, you can declare it as mutable:
class Integer
{
https://riptutorial.com/ 279
public:
Integer(int i_): i{i_}{}
protected:
int i;
mutable std::mutex mut;
};
https://riptutorial.com/ 280
Chapter 49: Function Template Overloading
Remarks
• A normal function is never related to a function template, despite same name, same type.
• A normal function call and a generated function template call are different even if they share
the same name, same return type and same argument list
Examples
What is a valid function template overloading?
A function template can be overloaded under the rules for non-template function overloading
(same name, but different parameter types) and in addition to that, the overloading is valid if
For a normal function, comparing two parameter types is is easy for the compiler, since it has all
informat. But a type within a template may not be determined yet. Therefore, the rule for when two
parameter types are equal is approximative here and says that the non-depependend types and
values need to match and the spelling of dependent types and expressions needs to be the same
(more precisely, they need to conform to the so-called ODR-rules), except that template
parameters may be renamed. However, if under such different spellings, two values within the
types are deemed different, but will always instantiate to the same values, the overloading is
invalid, but no diagnostic is required from the compiler.
template<typename T>
void f(T*) { }
template<typename T>
void f(T) { }
This is a valid overload, as "T" and "T*" are different spellings. But the following is invalid, with no
diagnostic required
template<typename T>
void f(T (*x)[sizeof(T) + sizeof(T)]) { }
template<typename T>
void f(T (*x)[2 * sizeof(T)]) { }
https://riptutorial.com/ 281
Chapter 50: Futures and Promises
Introduction
Promises and Futures are used to ferry a single object from one thread to another.
A std::future object can be used to retrieve a value, to test to see if a value is available, or to halt
execution until the value is available.
Examples
std::future and std::promise
{
auto promise = std::promise<std::string>();
producer.join();
consumer.join();
}
This code implements a version of std::async, but it behaves as if async were always called with
the deferred launch policy. This function also does not have async's special future behavior; the
returned future can be destroyed without ever acquiring its value.
template<typename F>
auto async_deferred(F&& func) -> std::future<decltype(func())>
{
using result_type = decltype(func());
std::thread(std::bind([=](std::promise<result_type>& promise)
https://riptutorial.com/ 282
{
try
{
promise.set_value(func());
// Note: Will not work with std::promise<void>. Needs some meta-template
programming which is out of scope for this example.
}
catch(...)
{
promise.set_exception(std::current_exception());
}
}, std::move(promise))).detach();
return future;
}
std::packaged_task bundles a function and the associated promise for its return type:
template<typename F>
auto async_deferred(F&& func) -> std::future<decltype(func())>
{
auto task = std::packaged_task<decltype(func())()>(std::forward<F>(func));
auto future = task.get_future();
std::thread(std::move(task)).detach();
return std::move(future);
}
The thread starts running immediately. We can either detach it, or have join it at the end of the
scope. When the function call to std::thread finishes, the result is ready.
Note that this is slightly different from std::async where the returned std::future when destructed
will actually block until the thread is finished.
If constraints for std::promise and std::future are not met an exception of type std::future_error is
thrown.
The error code member in the exception is of type std::future_errc and values are as below, along
with some test cases:
Inactive promise:
https://riptutorial.com/ 283
int test()
{
std::promise<int> pr;
return 0; // returns ok
}
int test()
{
std::promise<int> pr;
auto fut = pr.get_future(); //blocks indefinitely!
return 0;
}
Double retrieval:
int test()
{
std::promise<int> pr;
auto fut1 = pr.get_future();
try{
auto fut2 = pr.get_future(); // second attempt to get future
return 0;
}
catch(const std::future_error& e)
{
cout << e.what() << endl; // Error: "The future has already been retrieved
from the promise or packaged_task."
return -1;
}
return fut2.get();
}
int test()
{
std::promise<int> pr;
auto fut = pr.get_future();
try{
std::promise<int> pr2(std::move(pr));
pr2.set_value(10);
pr2.set_value(10); // second attempt to set promise throws exception
}
catch(const std::future_error& e)
{
cout << e.what() << endl; // Error: "The state of the promise has already been
set."
return -1;
}
return fut.get();
}
https://riptutorial.com/ 284
In the following naive parallel merge sort example, std::async is used to launch multiple parallel
merge_sort tasks. std::future is used to wait for the results and synchronize them:
#include <iostream>
using namespace std;
while((h<=mid)&&(j<=high))
{
if(num[h]<=num[j])
{
copy[i]=num[h];
h++;
}
else
{
copy[i]=num[j];
j++;
}
i++;
}
if(h>mid)
{
for(k=j;k<=high;k++)
{
copy[i]=num[k];
i++;
}
}
else
{
for(k=h;k<=mid;k++)
{
copy[i]=num[k];
i++;
}
}
for(k=low;k<=high;k++)
swap(num[k],copy[k]);
}
https://riptutorial.com/ 285
auto future2 = std::async(std::launch::deferred, [&]()
{
merge_sort(mid+1,high,num) ;
});
future1.get();
future2.get();
merge(low,mid,high,num);
}
}
Note: In the example std::async is launched with policy std::launch_deferred. This is to avoid a
new thread being created in every call. In the case of our example, the calls to std::async are
made out of order, the they synchronize at the calls for std::future::get().
https://riptutorial.com/ 286
Chapter 51: Header Files
Remarks
In C++, as in C, the C++ compiler and compilation process makes use of the C preprocessor. As
specified by the GNU C Preprocessor manual, a header file is defined as the following:
A header file is a file containing C declarations and macro definitions (see Macros) to
be shared between several source files. You request the use of a header file in your
program by including it, with the C preprocessing directive ‘#include’.
• System header files declare the interfaces to parts of the operating system. You
include them in your program to supply the definitions and declarations you need
to invoke system calls and libraries.
• Your own header files contain declarations for interfaces between the source files
of your program. Each time you have a group of related declarations and macro
definitions all or most of which are needed in several different source files, it is a
good idea to create a header file for them.
However, to the C preprocessor itself, a header file is no different than a source file.
The header/source file organization scheme is simply a strongly-held and standard convention set
by various software projects in order to provide separation between interface and implementation.
Although it is not formally enforced by the C++ Standard itself, following the header/source file
convention is highly recommended, and, in practice, is already almost ubiquitous.
Note that header files may be replaced as a project file structure convention by the upcoming
feature of modules, which is still to be considered for inclusion in a future C++ Standard as of the
time of writing (e.g. C++20).
Examples
Basic Example
The following example will contain a block of code that is meant to be split into several source
files, as denoted by // filename comments.
Source Files
// my_function.h
https://riptutorial.com/ 287
* Header functions usually do not define implementations for declarations
* unless code must be further processed at compile time, as in templates.
*/
/* Also, usually header files include preprocessor guards so that every header
* is never included twice.
*
* The guard is implemented by checking if a header-file unique preprocessor
* token is defined, and only including the header if it hasn't been included
* once before.
*/
#ifndef MY_FUNCTION_H
#define MY_FUNCTION_H
#endif // MY_FUNCTION_H
// my_function.cpp
/* Note how the corresponding source file for the header includes the interface
* defined in the header so that the compiler is aware of what the source file is
* implementing.
*
* In this case, the source file requires knowledge of the global constant
* global_value only defined in my_function.h. Without inclusion of the header
* file, this source file would not compile.
*/
#include "my_function.h" // or #include "my_function.hpp"
int my_function() {
return global_value; // return 42;
}
Header files are then included by other source files that want to use the functionality defined by
the header interface, but don't require knowledge of its implementation (thus, reducing code
coupling). The following program makes use of the header my_function.h as defined above:
// main.cpp
https://riptutorial.com/ 288
making use of the header/source file convention will usually do the following.
Assuming that the header file and source code file is already in the same directory, a programmer
would execute the following commands:
Alternatively, if one wishes to compile main.cpp to an object file first, and then link only object files
together as the final step:
g++ -c my_function.cpp
g++ -c main.cpp
Templates require compile-time generation of code: a templated function, for example, will be
effectively turned into multiple distinct functions once a templated function is parameterized by use
in source code.
This means that template function, member function, and class definitions cannot be delegated to
a separate source code file, as any code that will use any templated construct requires knowledge
of its definition to generally generate any derivative code.
Thus, templated code, if put in headers, must also contain its definition. An example of this is
below:
// templated_function.h
https://riptutorial.com/ 289
Chapter 52: Implementation-defined behavior
Examples
Char might be unsigned or signed
The standard doesn't specify if char should be signed or unsigned. Different compilers implement it
differently, or might allow to change it using a command line switch.
• char
• Signed integer types
• Unsigned integer types
• char16_t and char32_t
• bool
• wchar_t
With the exception of sizeof(char) / sizeof(signed char) / sizeof(unsigned char), which is split
between § 3.9.1.1 [basic.fundamental/1] and § 5.3.3.1 [expr.sizeof], and sizeof(bool), which is
entirely implementation-defined and has no minimum size, the minimum size requirements of
these types are given in section § 3.9.1 [basic.fundamental] of the standard, and shall be detailed
below.
Size of char
All versions of the C++ standard specify, in § 5.3.3.1, that sizeof yields 1 for unsigned char, signed
char, and char (it is implementation defined whether the char type is signed or unsigned).
C++14
char is large enough to represent 256 different values, to be suitable for storing UTF-8 code units.
https://riptutorial.com/ 290
C++11
Prior to C++11, long long and unsigned long long were not officially part of the C++ standard.
However, after their introduction to C, in C99, many compilers supported long long as an extended
signed integer type, and unsigned long long as an extended unsigned integer type, with the same
rules as the C types.
C++11
Specific minimum sizes for each type are not given by the standard. Instead, each type has a
minimum range of values it can support, which is, as specified in § 3.9.1.3, inherited from the C
standard, in §5.2.4.2.1. The minimum size of each type can be roughly inferred from this range, by
determining the minimum number of bits required; note that for any given platform, any type's
actual supported range may be larger than the minimum. Note that for signed types, ranges
correspond to one's complement, not the more commonly used two's complement; this is to allow
a wider range of platforms to comply with the standard.
Minimum bits
Type Minimum range
required
unsigned
short 0 to 65,535 (0 to 216 - 1) 16
https://riptutorial.com/ 291
Minimum bits
Type Minimum range
required
unsigned long
long 0 to 18,446,744,073,709,551,615 (0 to 264 - 1) 64
As each type is allowed to be greater than its minimum size requirement, types may differ in size
between implementations. The most notable example of this is with the 64-bit data models LP64
and LLP64, where LLP64 systems (such as 64-bit Windows) have 32-bit ints and longs, and LP64
systems (such as 64-bit Linux) have 32-bit ints and 64-bit longs. Due to this, integer types cannot
be assumed to have a fixed width across all platforms.
C++11
If integer types with fixed width are required, use types from the <cstdint> header, but note that the
standard makes it optional for implementations to support the exact-width types int8_t, int16_t,
int32_t, int64_t, intptr_t, uint8_t, uint16_t, uint32_t, uint64_t and uintptr_t.
C++11
The sizes of char16_t and char32_t are implementation-defined, as specified in § 5.3.3.1, with the
stipulations given in § 3.9.1.5:
• char16_tis large enough to represent any UTF-16 code unit, and has the same size,
signedness, and alignment as uint_least16_t; it is thus required to be at least 16 bits in size.
• char32_tis large enough to represent any UTF-32 code unit, and has the same size,
signedness, and alignment as uint_least32_t; it is thus required to be at least 32 bits in size.
Size of bool
Size of wchar_t
wchar_t, as specified in § 3.9.1.5, is a distinct type, whose range of values can represent every
distinct code unit of the largest extended character set among the supported locales. It has the
same size, signedness, and alignment as one of the other integral types, which is known as its
underlying type. This type's size is implementation-defined, as specified in § 5.3.3.1, and may be,
for example, at least 8, 16, or 32 bits; if a system supports Unicode, for example, wchar_t is
https://riptutorial.com/ 292
required to be at least 32 bits (an exception to this rule is Windows, where wchar_t is 16 bits for
compatibility purposes). It is inherited from the C90 standard, ISO 9899:1990 § 4.1.5, with only
minor rewording.
Depending on the implementation, the size of wchar_t is often, but not always, 8, 16, or 32 bits.
The most common examples of these are:
• In Unix and Unix-like systems, wchar_t is 32-bit, and is usually used for UTF-32.
• In Windows, wchar_t is 16-bit, and is used for UTF-16.
• On a system which only has 8-bit support, wchar_t is 8 bit.
C++11
If Unicode support is desired, it is recommended to use char for UTF-8, char16_t for UTF-16, or
char32_t for UTF-32, instead of using wchar_t.
Data Models
As mentioned above, the widths of integer types can differ between platforms. The most common
models are as follows, with sizes specified in bits:
LP32 (2/4/4) 16 32 32
ILP32 (4/4/4) 32 32 32
LLP64 (4/4/8) 32 32 64
LP64 (4/8/8) 32 64 64
Note, however, that these models aren't specifically mentioned in the standard itself.
In C++, a byte is the space occupied by a char object. The number of bits in a byte is given by
CHAR_BIT, which is defined in climits and required to be at least 8. While most modern systems
have 8-bit bytes, and POSIX requires CHAR_BIT to be exactly 8, there are some systems where
https://riptutorial.com/ 293
CHAR_BIT is greater than 8 i.e a single byte may be comprised of 8, 16, 32 or 64 bits.
int x = 42;
int* p = &x;
long addr = reinterpret_cast<long>(p);
std::cout << addr << "\n"; // prints some numeric address,
// probably in the architecture's native address format
The right way to store a pointer as an integer is using the uintptr_t or intptr_t types:
uintptr_t uip;
C++11
std::uintptr_t uip;
C++11 refers to C99 for the definition uintptr_t (C99 standard, 6.3.2.3):
an unsigned integer type with the property that any valid pointer to void can be
converted to this type, then converted back to pointer to void, and the result will
compare equal to the original pointer.
While, for the majority of modern platforms, you can assume a flat address space and that
arithmetic on uintptr_t is equivalent to arithmetic on char *, it's entirely possible for an
implementation to perform any transformation when casting void * to uintptr_t as long the
transformation can be reversed when casting back from uintptr_t to void *.
Technicalities
• On XSI-conformant (X/Open System Interfaces) systems, intptr_t and uintptr_t types are
required, otherwise they are optional.
• Within the meaning of the C standard, functions aren't objects; it isn't guaranteed by the C
standard that uintptr_t can hold a function pointer. Anyway POSIX (2.12.3) conformance
requires that:
All function pointer types shall have the same representation as the type pointer
https://riptutorial.com/ 294
to void. Conversion of a function pointer to void * shall not alter the
representation. A void * value resulting from such a conversion can be converted
back to the original function pointer type, using an explicit cast, without loss of
information.
• C99 §7.18.1:
When typedef names differing only in the absence or presence of the initial u are
defined, they shall denote corresponding signed and unsigned types as
described in 6.2.5; an implementation providing one of these corresponding types
shall also provide the other.
uintptr_tmight make sense if you want to do things to the bits of the pointer that you can't
do as sensibly with a signed integer.
The ranges of the integer types are implementation-defined. The header <limits> provides the
std::numeric_limits<T> template which provides the minimum and maximum values of all
fundamental types. The values satisfy guarantees provided by the C standard through the
<climits> and (>= C++11) <cinttypes> headers.
C++11
https://riptutorial.com/ 295
• std::numeric_limits<unsigned long long>::max() equals ULLONG_MAX, which is greater than or
equal to 18446744073709551615.
For floating-point types T, max() is the maximum finite value while min() is the minimum positive
normalized value. Additional members are provided for floating-point types, which are also
implementation-defined but satisfy certain guarantees provided by the C standard through the
<cfloat> header.
The standard requires that long double provides at least as much precision as double, which
provides at least as much precision as float; and that a long double can represent any value that a
double can represent, while a double can represent any value that a float can represent. The
details of the representation are, however, implementation-defined.
For a floating point type T, std::numeric_limits<T>::radix specifies the radix used by the
representation of T.
When either a signed or unsigned integer is converted to a signed integer type, and its value is not
representable in the destination type, the value produced is implementation-defined. Example:
// Suppose that on this implementation, the range of signed char is -128 to +127 and
// the range of unsigned char is 0 to 255
int x = 12345;
signed char sc = x; // sc has an implementation-defined value
https://riptutorial.com/ 296
unsigned char uc = x; // uc is initialized to 57 (i.e., 12345 modulo 256)
If the underlying type is not explicitly specified for an unscoped enumeration type, it is determined
in an implementation-defined manner.
enum E {
RED,
GREEN,
BLUE,
};
using T = std::underlying_type<E>::type; // implementation-defined
However, the standard does require the underlying type of an enumeration to be no larger than int
unless both int and unsigned int are unable to represent all the values of the enumeration.
Therefore, in the above code, T could be int, unsigned int, or short, but not long long, to give a few
examples.
Note that an enum has the same size (as returned by sizeof) as its underlying type.
https://riptutorial.com/ 297
Chapter 53: Inline functions
Introduction
A function defined with the inline specifier is an inline function. An inline function can be multiply
defined without violating the One Definition Rule, and can therefore be defined in a header with
external linkage. Declaring a function inline hints to the compiler that the function should be inlined
during code generation, but does not provide a guarantee.
Syntax
• inline function_declaration
• inline function_definition
• class { function_definition };
Remarks
Usually if code generated for a function is sufficiently small then it's a good candidate to be inlined.
Why so? If a function is large and is inlined in a loop, for all the calls made, the large function's
code would be duplicated leading to the generated binary size bloat. But, how small is sufficient?
While inline functions seem to be great way to avoid function calling overhead, it's to be noted that
not all functions that are marked inline are inlined. In other words, when you say inline, it is only
a hint to the compiler, not an order: the compiler isn't obliged to inline the function, it's free to
ignore it - most of them do. Modern compilers are better at making such optimisations that this
keyword is now a vestige of the past, when this suggestion of function inlining by the programmer
was taken seriously by the compilers. Even functions not marked inline are inlined by the
compiler when it sees benefit in doing so.
FAQs
When should I write the keyword 'inline' for a function/method in C++?
https://riptutorial.com/ 298
Only when you want the function to be defined in a header. More exactly only when the function's
definition can show up in multiple compilation units. It's a good idea to define small (as in one
liner) functions in the header file as it gives the compiler more information to work with while
optimizing your code. It also increases compilation time.
When should I not write the keyword 'inline' for a function/method in C++?
Don't add inline when you think your code will run faster if the compiler inlines it.
When will the the compiler not know when to make a function/method inline?
Generally, the compiler will be able to do this better than you. However, the compiler doesn't have
the option to inline code if it doesn't have the function definition. In maximally optimized code
usually all private methods are inlined whether you ask for it or not.
See Also
• When should I write the keyword 'inline' for a function/method?
Examples
Non-member inline function declaration
// header (.hpp)
struct A
{
void i_am_inlined()
{
}
};
struct B
{
void i_am_NOT_inlined();
};
https://riptutorial.com/ 299
// source (.cpp)
void B::i_am_NOT_inlined()
{
}
int main()
{
int a = 1, b = 2;
int c = add(a, b);
}
In the above code, when add is inlined, the resulting code would become something like this
int main()
{
int a = 1, b = 2;
int c = a + b;
}
The inline function is nowhere to be seen, its body gets inlined into the caller's body. Had add not
been inlined, a function would be called. The overhead of calling a function -- such as creating a
new stack frame, copying arguments, making local variables, jump (losing locality of reference and
there by cache misses), etc. -- has to be incurred.
https://riptutorial.com/ 300
Chapter 54: Inline variables
Introduction
An inline variable is allowed to be defined in multiple translation units without violating the One
Definition Rule. If it is multiply defined, the linker will merge all definitions into a single object in the
final program.
Examples
Defining a static data member in the class definition
A static data member of the class may be fully defined within the class definition if it is declared
inline. For example, the following class may be defined in a header. Prior to C++17, it would have
been necessary to provide a .cpp file to contain the definition of Foo::num_instances so that it would
be defined only once, but in C++17 the multiple definitions of the inline variable Foo::num_instances
all refer to the same int object.
class MyString {
public:
MyString() { /* ... */ }
// ...
static constexpr int max_size = INT_MAX / 2;
};
// in C++14, this definition was required in a single translation unit:
// constexpr int MyString::max_size;
https://riptutorial.com/ 301
Chapter 55: Internationalization in C++
Remarks
The C++ language does not dictate any character-set, some compilers may support the use of
UTF-8, or even UTF-16. However there is no certainty that anything beyond simple ANSI/ASCII
characters will be provided.
Thus all international language support is implementation defined, reliant on what platform,
operating system, and compiler you may be using.
Several third party libraries (such as the International Unicode Committee Library) that can be
used to extend the international support of the platform.
Examples
Understanding C++ string characteristics
#include <iostream>
#include <string>
int main()
{
const char * C_String = "This is a line of text w";
const char * C_Problem_String = "This is a line of text ኚ";
std::string Std_String("This is a second line of text w");
std::string Std_Problem_String("This is a second line of ϵx ኚ");
Depending on platform (windows, OSX, etc) and compiler (GCC, MSVC, etc), this program may
fail to compile, display different values, or display the same values.
String Length: 31
String Length: 31
CString Length: 24
CString Length: 24
This shows that under MSVC each of the extended-characters used is considered a single
"character", and this platform fully supports internationalised languages.
It should be noted however that this behaviour is unusual, these international characters are
https://riptutorial.com/ 302
stored internally as Unicode and thus are actually several bytes long. This may cause
unexpected errors
String Length: 31
String Length: 36
CString Length: 24
CString Length: 26
This example demonstrates that while the GCC compiler used on this (Linux) platform does
support these extended-characters, it also uses (correctly) several bytes to store an individual
character.
In this case the use of Unicode characters is possible, but the programmer must take great care in
remembering that the length of a "string" in this scenario is the length in bytes, not the length in
readable characters.
These differences are due to how international languages are handled on a per-platform basis -
and more importantly, that the C and C++ strings used in this example can be considered an
array of bytes, such that (for this usage) the C++ language considers a character (char) to be
a single byte.
https://riptutorial.com/ 303
Chapter 56: Iteration
Examples
break
continue
int sum = 0;
for (int i = 0; i < N; i++) {
int x;
std::cin >> x;
if (x < 0) continue;
sum += x;
// equivalent to: if (x >= 0) sum += x;
}
do
for
Introduces a for loop or, in C++11 and later, a range-based for loop.
// print 10 asterisks
for (int i = 0; i < 10; i++) {
https://riptutorial.com/ 304
putchar('*');
}
while
int i = 0;
// print 10 asterisks
while (i < 10) {
putchar('*');
i++;
}
https://riptutorial.com/ 305
Chapter 57: Iterators
Examples
C Iterators (Pointers)
#ifdef BEFORE_CPP11
// You can use `sizeof` to determine how many elements are in an array.
const int* first = array;
const int* afterLast = first + sizeof(array) / sizeof(array[0]);
// Then you can iterate over the array by incrementing a pointer until
// it reaches past the end of our array.
for (const int* i = first; i < afterLast; ++i) {
std::cout << *i << std::endl;
}
#else
// With C++11, you can let the STL compute the start and end iterators:
for (auto i = std::begin(array); i != std::end(array); ++i) {
std::cout << *i << std::endl;
}
#endif
This code would output the numbers 1 through 5, one on each line like this:
1
2
3
4
5
Breaking It Down
This line creates a new integer array with 5 values. C arrays are just pointers to memory where
each value is stored together in a contiguous block.
These lines create two pointers. The first pointer is given the value of the array pointer, which is
the address of the first element in the array. The sizeof operator when used on a C array returns
https://riptutorial.com/ 306
the size of the array in bytes. Divided by the size of an element this gives the number of elements
in the array. We can use this to find the address of the block after the array.
Here we create a pointer which we will use as an iterator. It is initialized with the address of the
first element we want to iterate over, and we'll continue to iterate as long as i is less than
afterLast, which means as long as i is pointing to an address within array.
Finally, within the loop we can access the value our iterator i is pointing to by dereferencing it.
Here the dereference operator * returns the value at the address in i.
Overview
A B C
+---+---+---+---+
| A | B | C | |
+---+---+---+---+
Elements are things within a sequence. Positions are places where meaningful operations can
happen to the sequence. For example, one inserts into a position, before or after element A, not
into an element. Even deletion of an element (erase(A)) is done by first finding its position, then
deleting it.
One can think of an iterator as dereferencing to the value it refers to in the sequence. This is
especially useful in understanding why you should never dereference the end() iterator in a
sequence:
https://riptutorial.com/ 307
+---+---+---+---+
| A | B | C | |
+---+---+---+---+
↑ ↑
| +-- An iterator here has no value. Do not dereference it!
+-------------- An iterator here dereferences to the value A.
In all the sequences and containers found in the C++ standard library, begin() will return an
iterator to the first position, and end() will return an iterator to one past the last position (not the last
position!). Consequently, the names of these iterators in algorithms are oftentimes labelled first
and last:
+---+---+---+---+
| A | B | C | |
+---+---+---+---+
↑ ↑
| |
+- first +- last
It is also possible to obtain an iterator to any sequence, because even an empty sequence
contains at least one position:
+---+
| |
+---+
In an empty sequence, begin() and end() will be the same position, and neither can be
dereferenced:
+---+
| |
+---+
↑
|
+- empty_sequence.begin()
|
+- empty_sequence.end()
The alternative visualization of iterators is that they mark the positions between elements:
+---+---+---+
| A | B | C |
+---+---+---+
↑ ^ ^ ↑
| |
+- first +- last
and dereferencing an iterator returns a reference to the element coming after the iterator. Some
situations where this view is particularly useful are:
• insert operations will insert elements into the position indicated by the iterator,
• erase operations will return an iterator corresponding to the same position as the one passed
https://riptutorial.com/ 308
in,
• an iterator and its corresponding reverse iterator are located in the same .position between
elements
Invalid Iterators
An iterator becomes invalidated if (say, in the course of an operation) its position is no longer a
part of a sequence. An invalidated iterator cannot be dereferenced until it has been reassigned to
a valid position. For example:
std::vector<int>::iterator first;
{
std::vector<int> foo;
first = foo.begin(); // first is now valid
} // foo falls out of scope and is destroyed
// At this point first is now invalid
The many algorithms and sequence member functions in the C++ standard library have rules
governing when iterators are invalidated. Each algorithm is different in the way they treat (and
invalidate) iterators.
Note, second argument of std::distance should be reachable from the first one(or, in other words
first should be less or equal than second).
Even though you can perform arithmetic operators with iterators, not all operations are defined for
all types of iterators. a = b + 3; would work for Random Access Iterators, but wouldn't work for
Forward or Bidirectional Iterators, which still can be advanced by 3 position with something like b =
a; ++b; ++b; ++b;. So it is recommended to use special functions in case you are not sure what is
iterator type (for example, in a template function accepting iterator).
https://riptutorial.com/ 309
Iterator Concepts
The C++ standard describes several different iterator concepts. These are grouped according to
how they behave in the sequences they refer to. If you know the concept an iterator models
(behaves like), you can be assured of the behavior of that iterator regardless of the sequence to
which it belongs. They are often described in order from the most to least restrictive (because the
next iterator concept is a step better than its predecessor):
• Input Iterators : Can be dereferenced only once per position. Can only advance, and only
one position at a time.
• Forward Iterators : An input iterator that can be dereferenced any number of times.
• Bidirectional Iterators : A forward iterator that can also advance backwards one position at a
time.
• Random Access Iterators : A bidirectional iterator that can advance forwards or backwards
any number of positions at a time.
• Contiguous Iterators (since C++17) : A random access iterator that guaranties that
underlying data is contiguous in memory.
Algorithms can vary depending on the concept modeled by the iterators they are given. For
example, although random_shuffle can be implemented for forward iterators, a more efficient
variant that requires random access iterators could be provided.
Iterator traits
Iterator traits provide uniform interface to the properties of iterators. They allow you to retrieve
value, difference, pointer, reference types and also category of iterator:
template<class Iter>
Iter find(Iter first, Iter last, typename std::iterator_traits<Iter>::value_type val) {
while (first != last) {
if (*first == val)
return first;
++first;
}
return last;
}
template<class BidirIt>
void test(BidirIt a, std::bidirectional_iterator_tag) {
std::cout << "Bidirectional iterator is used" << std::endl;
}
template<class ForwIt>
void test(ForwIt a, std::forward_iterator_tag) {
std::cout << "Forward iterator is used" << std::endl;
}
https://riptutorial.com/ 310
template<class Iter>
void test(Iter a) {
test(a, typename std::iterator_traits<Iter>::iterator_category());
}
Categories of iterators are basically iterators concepts, except Contiguous Iterators don't have
their own tag, since it was found to break code.
Reverse Iterators
If we want to iterate backwards through a list or vector we can use a reverse_iterator. A reverse
iterator is made from a bidirectional, or random access iterator which it keeps as a member which
can be accessed through base().
To iterate backwards use rbegin() and rend() as the iterators for the end of the collection, and the
start of the collection respectively.
A reverse iterator can be converted to a forward iterator via the base() member function. The
relationship is that the reverse iterator references one element past the base() iterator:
std::vector<int>::reverse_iterator r = v.rbegin();
std::vector<int>::iterator i = r.base();
assert(&*r == &*(i-1)); // always true if r, (i-1) are dereferenceable
// and are not proxy iterators
+---+---+---+---+---+---+---+
| | 1 | 2 | 3 | 4 | 5 | |
+---+---+---+---+---+---+---+
↑ ↑ ↑ ↑
| | | |
rend() | rbegin() end()
| rbegin().base()
begin()
rend().base()
In the visualization where iterators mark positions between elements, the relationship is simpler:
+---+---+---+---+---+
| 1 | 2 | 3 | 4 | 5 |
+---+---+---+---+---+
↑ ↑
| |
| end()
| rbegin()
begin() rbegin().base()
rend()
https://riptutorial.com/ 311
rend().base()
Vector Iterator
If the vector object is const, both begin and end return a const_iterator. If you want a const_iterator
to be returned even if your vector is not const, you can use cbegin and cend.
Example:
#include <vector>
#include <iostream>
int main() {
std::vector<int> v = { 1, 2, 3, 4, 5 }; //intialize vector using an initializer_list
return 0;
}
Output:
12345
Map Iterator
Output:
a => 200
b => 100
c => 300
https://riptutorial.com/ 312
Stream Iterators
Stream iterators are useful when we need to read a sequence or print formatted data from a
container:
// Constructing stream iterators and copying data from stream into vector.
std::copy(
// Iterator which will read stream data as integers.
std::istream_iterator<int>(istr),
// Default constructor produces end-of-stream iterator.
std::istream_iterator<int>(),
std::back_inserter(v));
A common pattern in other languages is having a function that produces a "stream" of objects, and
being able to use loop-code to loop over it.
template<class T>
struct generator_iterator {
using difference_type=std::ptrdiff_t;
using value_type=T;
using pointer=T*;
using reference=T;
using iterator_category=std::input_iterator_tag;
std::optional<T> state;
std::function< std::optional<T>() > operation;
// we store the current element in "state" if we have one:
T operator*() const {
return *state;
}
// to advance, we invoke our operation. If it returns a nullopt
// we have reached the end:
generator_iterator& operator++() {
state = operation();
return *this;
}
generator_iterator operator++(int) {
auto r = *this;
++(*this);
return r;
}
// generator iterators are only equal if they are both in the "end" state:
https://riptutorial.com/ 313
friend bool operator==( generator_iterator const& lhs, generator_iterator const& rhs ) {
if (!lhs.state && !rhs.state) return true;
return false;
}
friend bool operator!=( generator_iterator const& lhs, generator_iterator const& rhs ) {
return !(lhs==rhs);
}
// We implicitly construct from a std::function with the right signature:
generator_iterator( std::function< std::optional<T>() > f ):operation(std::move(f))
{
if (operation)
state = operation();
}
// default all special member functions:
generator_iterator( generator_iterator && ) =default;
generator_iterator( generator_iterator const& ) =default;
generator_iterator& operator=( generator_iterator && ) =default;
generator_iterator& operator=( generator_iterator const& ) =default;
generator_iterator() =default;
};
live example.
We store the generated element early so we can more easily detect if we are already at the end.
As the function of an end generator iterator is never used, we can create a range of generator
iterators by only copying the std::function once. A default constructed generator iterator
compares equal to itself, and to all other end-generator-iterators.
https://riptutorial.com/ 314
Chapter 58: Keywords
Introduction
Keywords have fixed meaning defined by the C++ standard and cannot be used as identifiers. It is
illegal to redefine keywords using the preprocessor in any translation unit that includes a standard
library header. However, keywords lose their special meaning inside attributes.
Syntax
• asm (string-literal);
• noexcept(expression) // meaning 1
• noexcept(constant-expression) // meaning 2
• noexcept // meaning 2
• sizeof unary-expression
• sizeof(type-id)
• sizeof...(identifier) // since C++11
• typename nested-name-specifier identifier // meaning 1
• typename nested-name-specifier template(opt) simple-template-id // meaning 1
• typename identifier(opt) // meaning 2
• typename... identifier(opt) // meaning 2; since C++11
• typename identifier(opt) = type-id // meaning 2
• template <template-parameter-list> typename ...(opt) identifier(opt) // meaning 3
• template <template-parameter-list> typename identifier(opt) = id-expression // meaning 3
Remarks
The full list of keywords is as follows:
https://riptutorial.com/ 315
• default
• delete for memory management, for functions (since C++11)
• do
• double
• dynamic_cast
• else
• enum
• explicit
• export
• extern as declaration specifier, in linkage specification, for templates
• false
• float
• for
• friend
• goto
• if
• inline for functions, for namespaces (since C++11), for variables (since C++17)
• int
• long
• mutable
• namespace
• new
• noexcept (since C++11)
• nullptr (since C++11)
• operator
• private
• protected
• public
• register
• reinterpret_cast
• return
• short
• signed
• sizeof
• static
• static_assert (since C++11)
• static_cast
• struct
• switch
• template
• this
• thread_local (since C++11)
• throw
• true
• try
• typedef
• typeid
• typename
• union
• unsigned
• using to redeclare a name, to alias a namespace, to alias a type
• virtual for functions, for base classes
• void
• volatile
https://riptutorial.com/ 316
• wchar_t
• while
The tokens final and override are not keywords. They may be used as identifiers and have
special meaning only in certain contexts.
The tokens and, and_eq, bitand, bitor, compl, not, not_eq, or, or_eq, xor, and xor_eq are alternative
spellings of &&, &=, &, |, ~, !, !=, ||, |=, ^, and ^=, respectively. The standard does not treat them as
keywords, but they are keywords for all intents and purposes, since it is impossible to redefine
them or use them to mean anything other than the operators they represent.
The following topics contain detailed explanations of many of the keywords in C++, which serve
fundamental purposes such as naming basic types or controlling the flow of execution.
• Flow Control
• Iteration
• Literal Keywords
• Type Keywords
• Classes/Structures
Examples
asm
The asm keyword takes a single operand, which must be a string literal. It has an implementation-
defined meaning, but is typically passed to the implementation's assembler, with the assembler's
output being incorporated into the translation unit.
The asm statement is a definition, not an expression, so it may appear either at block scope or
namespace scope (including global scope). However, since inline assembly cannot be constrained
by the rules of the C++ language, asm may not appear inside a constexpr function.
Example:
explicit
https://riptutorial.com/ 317
1. When applied to a single-argument constructor, prevents that constructor from being used to
perform implicit conversions.
class MyVector {
public:
explicit MyVector(uint64_t size);
};
MyVector v1(100); // ok
uint64_t len1 = 100;
MyVector v2{len1}; // ok, len1 is uint64_t
int len2 = 100;
MyVector v3{len2}; // ill-formed, implicit conversion from int to uint64_t
Since C++11 introduced initializer lists, in C++11 and later, explicit can be applied to a
constructor with any number of arguments, with the same meaning as in the single-argument
case.
struct S {
explicit S(int x, int y);
};
S f() {
return {12, 34}; // ill-formed
return S{12, 34}; // ok
}
C++11
2. When applied to a conversion function, prevents that conversion function from being used to
perform implicit conversions.
class C {
const int x;
public:
C(int x) : x(x) {}
explicit operator int() { return x; }
};
C c(42);
int x = c; // ill-formed
int y = static_cast<int>(c); // ok; explicit conversion
noexcept
C++11
1. A unary operator that determines whether the evaluation of its operand can propagate an
exception. Note that the bodies of called functions are not examined, so noexcept can yield
false negatives. The operand is not evaluated.
#include <iostream>
#include <stdexcept>
void foo() { throw std::runtime_error("oops"); }
void bar() {}
struct S {};
https://riptutorial.com/ 318
int main() {
std::cout << noexcept(foo()) << '\n'; // prints 0
std::cout << noexcept(bar()) << '\n'; // prints 0
std::cout << noexcept(1 + 1) << '\n'; // prints 1
std::cout << noexcept(S()) << '\n'; // prints 1
}
In this example, even though bar() can never throw an exception, noexcept(bar()) is still false
because the fact that bar() cannot propagate an exception has not been explicitly specified.
2. When declaring a function, specifies whether or not the function can propagate an exception.
Alone, it declares that the function cannot propagate an exception. With a parenthesized
argument, it declares that the function can or cannot propagate an exception depending on
the truth value of the argument.
In this example, we have declared that f4, f5, and f6 cannot propagate exceptions. (Although
an exception can be thrown during execution of f6, it is caught and not allowed to propagate
out of the function.) We have declared that f2 may propagate an exception. When the
noexcept specifier is omitted, it is equivalent to noexcept(false), so we have implicitly declared
that f1 and f3 may propagate exceptions, even though exceptions cannot actually be thrown
during the execution of f3.
C++17
Whether or not a function is noexcept is part of the function's type: that is, in the example above, f1,
f2, and f3 have different types from f4, f5, and f6. Therefore, noexcept is also significant in function
pointers, template arguments, and so on.
void g1() {}
void g2() noexcept {}
void (*p1)() noexcept = &g1; // ill-formed, since g1 is not noexcept
void (*p2)() noexcept = &g2; // ok; types match
void (*p3)() = &g1; // ok; types match
void (*p4)() = &g2; // ok; implicit conversion
typename
1. When followed by a qualified name, typename specifies that it is the name of a type. This is
often required in templates, in particular, when the nested name specifier is a dependent
type other than the current instantiation. In this example, std::decay<T> depends on the
https://riptutorial.com/ 319
template parameter T, so in order to name the nested type type, we need to prefix the entire
qualified name with typename. For more deatils, see Where and why do I have to put the
"template" and "typename" keywords?
C++17
3. typename can also be used when declaring a template template parameter, preceding the
name of the parameter, just like class.
sizeof
A unary operator that yields the size in bytes of its operand, which may be either an expression or
a type. If the operand is an expression, it is not evaluated. The size is a constant expression of
type std::size_t.
int a[100];
std::cout << "The number of bytes in `a` is: " << sizeof a;
memset(a, 0, sizeof a); // zeroes out the array
https://riptutorial.com/ 320
C++11
Different keywords
void C++
1. When used as a function return type, the void keyword specifies that the function does not
return a value. When used for a function's parameter list, void specifies that the function
takes no parameters. When used in the declaration of a pointer, void specifies that the
pointer is "universal."
2. If a pointer's type is void *, the pointer can point to any variable that is not declared with the
const or volatile keyword. A void pointer cannot be dereferenced unless it is cast to another
type. A void pointer can be converted into any other type of data pointer.
3. A void pointer can point to a function, but not to a class member in C++.
Volatile C++
1. A type qualifier that you can use to declare that an object can be modified in the program by
the hardware.
volatile declarator ;
virtual C++
Parameters
https://riptutorial.com/ 321
3. access-specifier Defines the level of access to the base class, public, protected or private.
Can appear before or after the virtual keyword.
this pointer
1. The this pointer is a pointer accessible only within the nonstatic member functions of a class,
struct, or union type. It points to the object for which the member function is called. Static
member functions do not have a this pointer.
this->member-identifier
An object's this pointer is not part of the object itself; it is not reflected in the result of a sizeof
statement on the object. Instead, when a nonstatic member function is called for an object, the
address of the object is passed by the compiler as a hidden argument to the function. For
example, the following function call:
myDate.setMonth( 3 );
setMonth( &myDate, 3 );
The object's address is available from within the member function as the this pointer. Most
uses of this are implicit. It is legal, though unnecessary, to explicitly use this when
referring to members of the class. For example:
The expression *this is commonly used to return the current object from a member function:
return *this;
if (&Object != this) {
// do not execute in cases of self-reference
1. To implement exception handling in C++, you use try, throw, and catch expressions.
2. First, use a try block to enclose one or more statements that might throw an exception.
3. A throw expression signals that an exceptional condition—often, an error—has occurred in a
try block. You can use an object of any type as the operand of a throw expression. Typically,
https://riptutorial.com/ 322
this object is used to communicate information about the error. In most cases, we
recommend that you use the std::exception class or one of the derived classes that are
defined in the standard library. If one of those is not appropriate, we recommend that you
derive your own exception class from std::exception.
4. To handle exceptions that may be thrown, implement one or more catch blocks immediately
following a try block. Each catch block specifies the type of exception it can handle.
MyData md;
try {
// Code that could throw an exception
md = GetNetworkResource();
}
catch (const networkIOException& e) {
// Code that executes when an exception of type
// networkIOException is thrown in the try block
// ...
// Log error message in the exception object
cerr << e.what();
}
catch (const myDataFormatException& e) {
// Code that handles another exception type
// ...
cerr << e.what();
}
The code after the try clause is the guarded section of code. The throw expression
throws—that is, raises—an exception. The code block after the catch clause is the
exception handler. This is the handler that catches the exception that's thrown if the
types in the throw and catch expressions are compatible.
try {
throw CSomeOtherException();
}
catch(...) {
// Catch all exceptions – dangerous!!!
// Respond (perhaps only partially) to the exception, then
// re-throw to pass the exception to some other handler
// ...
throw;
}
friend (C++)
https://riptutorial.com/ 323
are not members of a class or to all members in a separate class. Only the class
implementer can declare who its friends are. A function or class cannot declare itself as a
friend of any class. In a class definition, use the friend keyword and the name of a non-
member function or other class to grant it access to the private and protected members of
your class. In a template definition, a type parameter can be declared as a friend.
2. If you declare a friend function that was not previously declared, that function is exported to
the enclosing nonclass scope.
class friend F
friend F;
class ForwardDeclared;// Class name is known.
class HasFriends
{
friend int ForwardDeclared::IsAFriend();// C2039 error expected
};
friend functions
1. A friend function is a function that is not a member of a class but has access to the class's
private and protected members.Friend functions are not considered class members; they are
normal external functions that are given special access privileges.
2. Friends are not in the class's scope, and they are not called using the member-selection
operators (. and –>) unless they are members of another class.
3. A friend function is declared by the class that is granting access. The friend declaration can
be placed anywhere in the class declaration. It is not affected by the access control
keywords.
#include <iostream>
private:
int m_i;
};
int main()
{
Point sPoint;
sPoint.PrintPrivate();
ChangePrivate(sPoint);
sPoint.PrintPrivate();
// Output: 0
1
https://riptutorial.com/ 324
}
class B;
class A {
public:
int Func1( B& b );
private:
int Func2( B& b );
};
class B {
private:
int _b;
https://riptutorial.com/ 325
Chapter 59: Lambdas
Syntax
• [default-capture, capture-list] (argument-list) mutable throw-specification attributes -> return-
type { lambda-body } // Order of lambda specifiers and attributes.
• [capture-list] (argument-list) { lambda-body } // Common lambda definition.
• [=] (argument-list) { lambda-body } // Captures all needed local variables by value.
• [&] (argument-list) { lambda-body } // Captures all needed local variables by reference.
• [capture-list] { lambda-body } // Argument list and specifiers can be omitted.
Parameters
Parameter Details
Specifies how local variables are made accessible within the lambda-body.
Variables without prefix are captured by value. Variables prefixed with & are
capture-list captured by reference. Within a class method, this can be used to make all
its members accessible by reference. Non-listed variables are inaccessible,
unless the list is preceded by a default-capture.
throw- (optional) Specifies the exception throwing behavior of the lambda function.
specification For example: noexcept or throw(std::exception).
(optional) Any attributes for the lambda function. For example, if the lambda-
attributes
body always throws an exception then [[noreturn]] can be used.
-> return- (optional) Specifies the return type of the lambda function. Required when the
type return type cannot be determined by the compiler.
Remarks
https://riptutorial.com/ 326
C++17 (the current draft) introduces constexpr lambdas, basically lambdas that can be evaluated
at compile time. A lambda is automatically constexpr if it satisfies constexpr requirements, but you
can also specify it using the constexpr keyword:
Examples
What is a lambda expression?
A lambda expression provides a concise way to create simple function objects. A lambda
expression is a prvalue whose result object is called closure object, which behaves like a function
object.
The name 'lambda expression' originates from lambda calculus, which is a mathematical
formalism invented in the 1930s by Alonzo Church to investigate questions about logic and
computability. Lambda calculus formed the basis of LISP, a functional programming language.
Compared to lambda calculus and LISP, C++ lambda expressions share the properties of being
unnamed, and to capture variables from the surrounding context, but they lack the ability to
operate on and return functions.
A lambda expression is often used as an argument to functions that take a callable object. That
can be simpler than creating a named function, which would be only used when passed as the
argument. In such cases, lambda expressions are generally preferred because they allow defining
the function objects inline.
A lambda consists typically of three parts: a capture list [], an optional parameter list () and a
body {}, all of which can be empty:
Capture list
[] is the capture list. By default, variables of the enclosing scope cannot be accessed by a
lambda. Capturing a variable makes it accessible inside the lambda, either as a copy or as a
reference. Captured variables become a part of the lambda; in contrast to function arguments,
they do not have to be passed when calling the lambda.
https://riptutorial.com/ 327
auto b = f(); // Call the lambda function. a is taken from the capture list
and not passed here.
Parameter list
() is the parameter list, which is almost the same as in regular functions. If the lambda takes no
arguments, these parentheses can be omitted (except if you need to declare the lambda mutable).
These two lambdas are equivalent:
C++14
The parameter list can use the placeholder type auto instead of actual types. By doing so, this
argument behaves like a template parameter of a function template. Following lambdas are
equivalent when you want to sort a vector in generic code:
Function body
Calling a lambda
A lambda expression's result object is a closure, which can be called using the operator() (as with
other function objects):
int multiplier = 5;
auto timesFive = [multiplier](int a) { return a * multiplier; };
std::out << timesFive(2); // Prints 10
multiplier = 15;
std::out << timesFive(2); // Still prints 2*5 == 10
Return Type
You can also manually specify the return type using the following syntax:
https://riptutorial.com/ 328
Mutable Lambda
Objects captured by value in the lambda are by default immutable. This is because the operator()
of the generated closure object is const by default.
auto func = [c = 0](){++c; std::cout << c;}; // fails to compile because ++c
// tries to mutate the state of
// the lambda.
Modifying can be allowed by using the keyword mutable, which make the closer object's operator()
non-const:
If used together with the return type, mutable comes before it.
auto func = [c = 0]() mutable -> int {++c; std::cout << c; return c;};
Before C++11:
C++11
// Declare a vector
const int arr[] = { 1, 2, 3, 4, 5 };
std::vector<int> vec(arr, arr+5);
// Find a number that's less than a given input (assume this would have been function input)
int threshold = 10;
std::vector<int>::iterator it = std::find_if(vec.begin(), vec.end(), islessthan(threshold));
Since C++11:
C++11
// Declare a vector
std::vector<int> vec{ 1, 2, 3, 4, 5 };
// Find a number that's less than a given input (assume this would have been function input)
https://riptutorial.com/ 329
int threshold = 10;
auto it = std::find_if(vec.begin(), vec.end(), [threshold](int value) { return value <
threshold; });
For lambdas with a single return statement, or multiple return statements whose expressions are
of the same type, the compiler can deduce the return type:
// Returns bool, because "value > 10" is a comparison which yields a Boolean result
auto l = [](int value) {
return value > 10;
}
For lambdas with multiple return statements of different types, the compiler can't deduce the return
type:
// error: return types must match if lambda has unspecified return type
auto l = [](int value) {
if (value < 10) {
return 1;
} else {
return 1.5;
}
};
The rules for this match the rules for auto type deduction. Lambdas without explicitly specified
return types never return references, so if a reference type is desired it must be explicitly specified
as well:
Capture by value
If you specify the variable's name in the capture list, the lambda will capture it by value. This
means that the generated closure type for the lambda stores a copy of the variable. This also
requires that the variable's type be copy-constructible:
int a = 0;
https://riptutorial.com/ 330
[a]() {
return a; // Ok, 'a' is captured by value
};
C++14
auto p = std::unique_ptr<T>(...);
From C++14 on, it is possible to initialize variables on the spot. This allows move only types to be
captured in the lambda.
C++14
auto p = std::make_unique<T>(...);
[p = std::move(p)]() {
return p->createWidget();
};
Even though a lambda captures variables by value when they are given by their name, such
variables cannot be modified within the lambda body by default. This is because the closure type
puts the lambda body in a declaration of operator() const.
The const applies to accesses to member variables of the closure type, and captured variables
that are members of the closure (all appearances to the contrary):
int a = 0;
[a]() {
a = 2; // Illegal, 'a' is accessed via `const`
decltype(a) a1 = 1;
a1 = 2; // valid: variable 'a1' is not const
};
To remove the const, you have to specify the keyword mutable on the lambda:
int a = 0;
[a]() mutable {
a = 2; // OK, 'a' can be modified
return a;
};
Because a was captured by value, any modifications done by calling the lambda will not affect a.
The value of a was copied into the lambda when it was constructed, so the lambda's copy of a is
separate from the external a variable.
https://riptutorial.com/ 331
int a = 5 ;
auto plus5Val = [a] (void) { return a + 5 ; } ;
auto plus5Ref = [&a] (void) {return a + 5 ; } ;
a = 7 ;
std::cout << a << ", value " << plus5Val() << ", reference " << plus5Ref() ;
// The result will be "7, value 10, reference 12"
Generalized capture
C++14
Lambdas can capture expressions, rather than just variables. This permits lambdas to store move-
only types:
auto p = std::make_unique<T>(...);
This moves the outer p variable into the lambda capture variable, also called p. lamb now owns the
memory allocated by make_unique. Because the closure contains a type that is non-copyable, this
means that lamb is itself non-copyable. But it can be moved:
Note that std::function<> requires that the values stored be copyable. You can write your own
move-only-requiring std::function, or you could just stuff the lambda into a shared_ptr wrapper:
takes our move-only lambda and stuffs its state into a shared pointer then returns a lambda that
can be copied, and then stored in a std::function or similar.
Generalized capture uses auto type deduction for the variable's type. It will declare these captures
as values by default, but they can be references as well:
int a = 0;
https://riptutorial.com/ 332
auto lamb = [&v = a](int add) //Note that `a` and `v` have different names
{
v += add; //Modifies `a`
};
Generalize capture does not need to capture an external variable at all. It can capture an arbitrary
expression:
This is useful for giving lambdas arbitrary values that they can hold and potentially modify, without
having to declare them externally to the lambda. Of course, that is only useful if you do not intend
to access those variables after the lambda has completed its work.
Capture by reference
If you precede a local variable's name with an &, then the variable will be captured by reference.
Conceptually, this means that the lambda's closure type will have a reference variable, initialized
as a reference to the corresponding variable from outside of the lambda's scope. Any use of the
variable in the lambda body will refer to the original variable:
set();
assert(a == 1);
Of course, capturing by reference means that the lambda must not escape the scope of the
variables it captures. So you could call functions that take a function, but you must not call a
function that will store the lambda beyond the scope of your references. And you must not return
the lambda.
Default capture
By default, local variables that are not explicitly specified in the capture list, cannot be accessed
from within the lambda body. However, it is possible to implicitly capture variables named by the
lambda body:
int a = 1;
https://riptutorial.com/ 333
int b = 2;
Explicit capturing can still be done alongside implicit default capturing. The explicit capture
definition will override the default capture:
int a = 0;
int b = 1;
[=, &b]() {
a = 2; // Illegal; 'a' is capture by value, and lambda is not 'mutable'
b = 2; // OK; 'b' is captured by reference
};
Generic lambdas
c++14
Lambda functions can take arguments of arbitrary types. This allows a lambda to be more generic:
int i = twice(2); // i == 4
std::string s = twice("hello"); // s == "hellohello"
This is implemented in C++ by making the closure type's operator() overload a template function.
The following type has equivalent behavior to the above lambda closure:
struct _unique_lambda_type
{
template<typename T>
auto operator() (T x) const {return x + x;}
};
Here, x is deduced based on the first function argument, while y will always be int.
Generic lambdas can take arguments by reference as well, using the usual rules for auto and &. If
a generic parameter is taken as auto&&, this is a forwarding reference to the passed in argument
and not an rvalue reference:
https://riptutorial.com/ 334
lamb1(x); // Illegal; must use `std::move(x)` for `int&&` parameters.
lamb2(x); // Legal; the type of `x` is deduced as `int&`.
or:
Here we are visiting in a polymorphic manner; but in other contexts, the names of the type we are
passing isn't interesting:
mutex_wrapped<std::ostream&> os = std::cout;
os.write([&](auto&& os){
os << "hello world\n";
});
Repeating the type of std::ostream& is noise here; it would be like having to mention the type of a
variable every time you use it. Here we are creating a visitor, but no a polymorphic one; auto is
used for the same reason you might use auto in a for(:) loop.
If a lambda's capture list is empty, then the lambda has an implicit conversion to a function pointer
that takes the same arguments and returns the same return type:
auto sorter = [](int lhs, int rhs) -> bool {return lhs < rhs;};
Calling this function pointer behaves exactly like invoking operator() on the lambda. This function
pointer is in no way reliant on the source lambda closure's existence. It therefore may outlive the
lambda closure.
https://riptutorial.com/ 335
This feature is mainly useful for using lambdas with APIs that deal in function pointers, rather than
C++ function objects.
C++14
Conversion to a function pointer is also possible for generic lambdas with an empty capture list. If
necessary, template argument deduction will be used to select the correct specialization.
auto sorter = [](auto lhs, auto rhs) { return lhs < rhs; };
using func_ptr = bool(*)(int, int);
func_ptr sorter_func = sorter; // deduces int, int
// note however that the following is ambiguous
// func_ptr sorter_func2 = +sorter;
A lambda expression evaluated in a class' member function is implicitly a friend of that class:
class Foo
{
private:
int i;
public:
Foo(int val) : i(val) {}
Such a lambda is not only a friend of that class, it has the same access as the class it is declared
within has.
Lambdas can capture the this pointer which represents the object instance the outer function was
called on. This is done by adding this to the capture list:
class Foo
{
private:
int i;
public:
Foo(int val) : i(val) {}
void Test()
https://riptutorial.com/ 336
{
// capture the this pointer by value
auto lamb = [this](int val)
{
i = val;
};
lamb(30);
}
};
When this is captured, the lambda can use member names of its containing class as though it
were in its containing class. So an implicit this-> is applied to such members.
Be aware that this is captured by value, but not the value of the type. It is captured by the value of
this, which is a pointer. As such, the lambda does not own this. If the lambda out lives the lifetime
of the object that created it, the lambda can become invalid.
This also means that the lambda can modify this without being declared mutable. It is the pointer
which is const, not the object being pointed to. That is, unless the outer member function was itself
a const function.
Also, be aware that the default capture clauses, both [=] and [&], will also capture this implicitly.
And they both capture it by the value of the pointer. Indeed, it is an error to specify this in the
capture list when a default is given.
C++17
Lambdas can capture a copy of the this object, created at the time the lambda is created. This is
done by adding *this to the capture list:
class Foo
{
private:
int i;
public:
Foo(int val) : i(val) {}
void Test()
{
// capture a copy of the object given by the this pointer
auto lamb = [*this](int val) mutable
{
i = val;
};
Lambda functions in C++ are syntactic sugar that provide a very concise syntax for writing functors
https://riptutorial.com/ 337
. As such, equivalent functionality can be obtained in C++03 (albeit much more verbose) by
converting the lambda function into a functor:
public:
// Constructor
inline Functor(T1 val, T2& ref) : val(val), ref(ref) {}
// Functor body
R operator()(int arg1, int arg2) const {
/* lambda-body */
return R();
}
};
If the lambda function is mutable then make the functor's call-operator non-const, i.e.:
https://riptutorial.com/ 338
Recursive lambdas
But a lambda cannot be recursive, it has no way to invoke itself. A lambda has no name and using
this within the body of a lambda refers to a captured this (assuming the lambda is created in the
body of a member function, otherwise it is an error). So how do we solve this problem?
Use std::function
This works, but should be used sparingly. It's slow (we're using type erasure now instead of a
direct function call), it's fragile (copying gcd or returning gcd will break since the lambda refers to
the original object), and it won't work with generic lambdas.
This adds a lot of indirection (which is overhead), but it can be copied/returned, and all copies
share state. It does let you return the lambda, and is otherwise less fragile than the above solution.
Use a Y-combinator
With the help of a short utility struct, we can solve all of these problems:
// a forwarding operator():
template <class... Args>
decltype(auto) operator()(Args&&... args) const {
// we pass ourselves to f, then the arguments.
// the lambda should take the first argument as `auto&& recurse` or similar.
return f(*this, std::forward<Args>(args)...);
}
https://riptutorial.com/ 339
};
// helper function that deduces the type of the lambda:
template <class F>
y_combinator<std::decay_t<F>> make_y_combinator(F&& f) {
return {std::forward<F>(f)};
}
// (Be aware that in C++17 we can do better than a `make_` function)
The y_combinator is a concept from the lambda calculus that lets you have recursion without being
able to name yourself until you are defined. This is exactly the problem lambdas have.
You create a lambda that takes "recurse" as its first argument. When you want to recurse, you
pass the arguments to recurse.
The y_combinator then returns a function object that calls that function with its arguments, but with
a suitable "recurse" object (namely the y_combinator itself) as its first argument. It forwards the rest
of the arguments you call the y_combinator with to the lambda as well.
In short:
and you have recursion in a lambda with no serious restrictions or significant overhead.
C++14
Parameter pack unpacking traditionally requires writing a helper function for each time you want to
do it.
template<std::size_t...Is>
void print_indexes( std::index_sequence<Is...> ) {
using discard=int[];
(void)discard{0,((void)(
std::cout << Is << '\n' // here Is is a compile-time constant.
),0)...};
}
template<std::size_t I>
void print_indexes_upto() {
https://riptutorial.com/ 340
return print_indexes( std::make_index_sequence<I>{} );
}
The print_indexes_upto wants to create and unpack a parameter pack of indexes. In order to do
so, it must call a helper function. Every time you want to unpack a parameter pack you created,
you end up having to create a custom helper function to do it.
You can unpack parameter packs into a set of invocations of a lambda, like this:
template<std::size_t I>
using index_t = std::integral_constant<std::size_t, I>;
template<std::size_t I>
constexpr index_t<I> index{};
template<class=void, std::size_t...Is>
auto index_over( std::index_sequence<Is...> ) {
return [](auto&& f){
using discard=int[];
(void)discard{0,(void(
f( index<Is> )
),0)...};
};
}
template<std::size_t N>
auto index_over(index_t<N> = {}) {
return index_over( std::make_index_sequence<N>{} );
}
C++17
template<class=void, std::size_t...Is>
auto index_over( std::index_sequence<Is...> ) {
return [](auto&& f){
((void)(f(index<Is>)), ...);
};
}
Once you have done that, you can use this to replace having to manually unpack parameter packs
with a second overload in other code, letting you unpack parameter packs "inline":
from_zero_to_N(
[&](auto i){
using std::get;
f( get<i>( std::forward<Tup>(tup) ) );
}
https://riptutorial.com/ 341
);
}
template<std::size_t I>
void print_indexes_upto() {
index_over(index<I>)([](auto i){
std::cout << i << '\n'; // here i is a compile-time constant
});
}
which is much shorter, and keeps logic in the code that uses it.
https://riptutorial.com/ 342
Chapter 60: Layout of object types
Remarks
See also Size of integral types.
Examples
Class types
By "class", we mean a type that was defined using the class or struct keyword (but not enum struct
or enum class).
• Even an empty class still occupies at least one byte of storage; it will therefore consist purely
of padding. This ensures that if p points to an object of an empty class, then p + 1 is a
distinct address and points to a distinct object. However, it is possible for an empty class to
have a size of 0 when used as a base class. See empty base optimisation.
• The object representation of a class type contains the object representations of the base
class and non-static member types. Therefore, for example, in the following class:
struct S {
int x;
char* y;
};
• If a class type has members and/or base classes with types t1, t2,...tN, the size must be at
least sizeof(t1) + sizeof(t2) + ... + sizeof(tN) given the preceding points. However,
depending on the alignment requirements of the members and base classes, the compiler
may be forced to insert padding between subobjects, or at the beginning or end of the
complete object.
https://riptutorial.com/ 343
struct TwoInts { int i, j; };
// sizeof(TwoInts) >= 2 * sizeof(int)
// Assuming a typical 32- or 64-bit system, sizeof(TwoInts) == 8 (4 + 4).
struct IntAndChar { int i; char c; };
// sizeof(IntAndChar) >= sizeof(int) + sizeof(char)
// Assuming a typical 32- or 64-bit system, sizeof(IntAndChar) == 8 (4 + 1 +
padding).
struct AnIntDerived : AnInt { long long l; };
// sizeof(AnIntDerived) >= sizeof(AnInt) + sizeof(long long)
// Assuming a typical 32- or 64-bit system, sizeof(AnIntDerived) == 16 (4 + padding +
8).
• If padding is inserted in an object due to alignment requirements, the size will be greater
than the sum of the sizes of the members and base classes. With n-byte alignment, size will
typically be the smallest multiple of n which is larger than the size of all members & base
classes. Each member memN will typically be placed at an address which is a multiple of
alignof(memN), and n will typically be the largest alignof out of all members' alignofs. Due to
this, if a member with a smaller alignof is followed by a member with a larger alignof, there
is a possibility that the latter member will not be aligned properly if placed immediately after
the former. In this case, padding (also known as an alignment member ) will be placed
between the two members, such that the latter member can have its desired alignment.
Conversely, if a member with a larger alignof is followed by a member with a smaller alignof
, no padding will usually be necessary. This process is also known as "packing".
Due to classes typically sharing the alignof of their member with the largest alignof, classes
will typically be aligned to the alignof of the largest built-in type they directly or indirectly
contain.
https://riptutorial.com/ 344
char c3[3];
short t;
int i;
};
// ShortChar3ArrShortInt has 4-byte alignment: alignof(int) >= alignof(char) &&
// alignof(int) >= alignof(short)
// sizeof(ShortChar3ArrShortInt) == 12 (2 (short) + 3 (char[3]) + 1 (padding) +
// 2 (short) + 4 (int))
// Note that t is placed at alignment of 2, not 4. alignof(short) == 2.
struct Large_1 {
ShortIntCharInt sici;
bool b;
ShortIntCharInt tjdj;
};
// Large_1 has 4-byte alignment.
// alignof(ShortIntCharInt) == alignof(int) == 4
// alignof(b) == 1
// Therefore, alignof(Large_1) == 4.
// sizeof(Large_1) == 36 (16 (ShortIntCharInt) + 1 (bool) + 3 (padding) +
// 16 (ShortIntCharInt))
struct Large_2 {
IntLLInt illi;
float f;
IntLLInt jmmj;
};
// Large_2 has 8-byte alignment.
// alignof(IntLLInt) == alignof(long long) == 8
// alignof(float) == 4
// Therefore, alignof(Large_2) == 8.
// sizeof(Large_2) == 56 (24 (IntLLInt) + 4 (float) + 4 (padding) + 24 (IntLLInt))
C++11
• If strict alignment is forced with alignas, padding will be used to force the type to meet the
specified alignment, even when it would otherwise be smaller. For example, with the
definition below, Chars<5> will have three (or possibly more) padding bytes inserted at the end
so that its total size is 8. It is not possible for a class with an alignment of 4 to have a size of
5 because it would be impossible to make an array of that class, so the size must be
"rounded up" to a multiple of 4 by inserting padding bytes.
• If two non-static members of a class have the same access specifier, then the one that
comes later in declaration order is guaranteed to come later in the object representation. But
if two non-static members have different access specifiers, their relative order within the
object is unspecified.
• It is unspecified what order the base class subobjects appear in within an object, whether
they occur consecutively, and whether they appear before, after, or between member
https://riptutorial.com/ 345
subobjects.
Arithmetic types
The signed char type has no padding bits, i.e., if signed char is 8 bits long, then it has 8 bits of
capacity to represent a number.
Note that these guarantees do not apply to types other than narrow character types.
Integer types
The unsigned integer types use a pure binary system, but may contain padding bits. For example,
it is possible (though unlikely) for unsigned int to be 64 bits long but only be capable of storing
integers between 0 and 232 - 1, inclusive. The other 32 bits would be padding bits, which should
not be written to directly.
The signed integer types use a binary system with a sign bit and possibly padding bits. Values that
belong to the common range of a signed integer type and the corresponding unsigned integer type
have the same representation. For example, if the bit pattern 0001010010101011 of an unsigned short
object represents the value 5291, then it also represents the value 5291 when interpreted as a short
object.
Arrays
An array type has no padding in between its elements. Therefore, an array with element type T is
just a sequence of T objects laid out in memory, in order.
https://riptutorial.com/ 346
A multidimensional array is an array of arrays, and the above applies recursively. For example, if
we have the declaration
int a[5][3];
then a is an array of 5 arrays of 3 ints. Therefore, a[0], which consists of the three elements
a[0][0], a[0][1], a[0][2], is laid out in memory before a[1], which consists of a[1][0], a[1][1], and
a[1][2]. This is called row major order.
https://riptutorial.com/ 347
Chapter 61: Linkage specifications
Introduction
A linkage specification tells the compiler to compile declarations in a way that allows them to be
linked together with declarations written in another language, such as C.
Syntax
• extern string-literal { declaration-seq(opt) }
• extern string-literal declaration
Remarks
The standard requires all compilers to support extern "C" in order to allow C++ to be compatible
with C, and extern "C++", which may be used to override an enclosing linkage specification and
restore the default. Other supported linkage specifications are implementation-defined.
Examples
Signal handler for Unix-like operating system
Since a signal handler will be called by the kernel using the C calling convention, we must tell the
compiler to use the C calling convention when compiling the function.
A C library header can usually be included into a C++ program, since most declarations are valid
in both C and C++. For example, consider the following foo.h:
https://riptutorial.com/ 348
typedef struct Foo {
int bar;
} Foo;
Foo make_foo(int);
The definition of make_foo is separately compiled and distributed with the header in object form.
A C++ program can #include <foo.h>, but the compiler will not know that the make_foo function is
defined as a C symbol, and will probably try to look for it with a mangled name, and fail to locate it.
Even if it can find the definition of make_foo in the library, not all platforms use the same calling
conventions for C and C++, and the C++ compiler will use the C++ calling convention when calling
make_foo, which is likely to cause a segmentation fault if make_foo is expecting to be called with the
C calling convention.
The way to remedy this problem is to wrap almost all the declarations in the header in an extern
"C" block.
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
} /* end of "extern C" block */
#endif
Now when foo.h is included from a C program, it will just appear as ordinary declarations, but
when foo.h is included from a C++ program, make_foo will be inside an extern "C" block and the
compiler will know to look for an unmangled name and use the C calling convention.
https://riptutorial.com/ 349
Chapter 62: Literals
Introduction
Traditionally, a literal is an expression denoting a constant whose type and value are evident from
its spelling. For example, 42 is a literal, while x is not since one must see its declaration to know its
type and read previous lines of code to know its value.
However, C++11 also added user-defined literals, which are not literals in the traditional sense but
can be used as a shorthand for function calls.
Examples
true
bool ok = true;
if (!f()) {
ok = false;
goto end;
}
false
bool ok = true;
if (!f()) {
ok = false;
goto end;
}
nullptr
C++11
A keyword denoting a null pointer constant. It can be converted to any pointer or pointer-to-
member type, yielding a null pointer of the resulting type.
Note that nullptr is not itself a pointer. The type of nullptr is a fundamental type known as
std::nullptr_t.
https://riptutorial.com/ 350
void f(int* p);
int main() {
f(nullptr); // ok
g(nullptr); // error
h(nullptr); // ok
}
this
Within a member function of a class, the keyword this is a pointer to the instance of the class on
which the function was called. this cannot be used in a static member function.
struct S {
int x;
S& operator=(const S& other) {
x = other.x;
// return a reference to the object being assigned to
return *this;
}
};
The type of this depends on the cv-qualification of the member function: if X::f is const, then the
type of this within f is const X*, so this cannot be used to modify non-static data members from
within a const member function. Likewise, this inherits volatile qualification from the function it
appears in.
C++11
struct S;
struct T {
T(const S* s);
// ...
};
struct S {
// ...
T t{this};
};
Integer literal
• decimal-literal
https://riptutorial.com/ 351
It is a non-zero decimal digit (1, 2, 3, 4, 5, 6, 7, 8, 9), followed by zero or more decimal digits (0, 1,
2, 3, 4, 5, 6, 7, 8, 9)
int d = 42;
• octal-literal
It is the digit zero (0) followed by zero or more octal digits (0, 1, 2, 3, 4, 5, 6, 7)
int o = 052
• hex-literal
It is the character sequence 0b or the character sequence 0B followed by one or more binary
digits (0, 1)
Integer-suffix, if provided, may contain one or both of the following (if both are provided, they may
appear in any order:
• long-suffix (the character l or the character L) or the long-long-suffix (the character sequence
ll or the character sequence LL) (since C++11)
Notes
Letters in the integer literals are case-insensitive: 0xDeAdBaBeU and 0XdeadBABEu represent
the same number (one exception is the long-long-suffix, which is either ll or LL, never lL or Ll)
There are no negative integer literals. Expressions such as -1 apply the unary minus operator to
the value represented by the literal, which may involve implicit type conversions.
In C prior to C99 (but not in C++), unsuffixed decimal values that do not fit in long int are allowed
to have the type unsigned long int.
https://riptutorial.com/ 352
When used in a controlling expression of #if or #elif, all signed integer constants act as if they
have type std::intmax_t and all unsigned integer constants act as if they have type std::uintmax_t.
https://riptutorial.com/ 353
Chapter 63: Loops
Introduction
A loop statement executes a group of statements repeatedly until a condition is met. There are 3
types of primitive loops in C++: for, while, and do...while.
Syntax
• while (condition) statement ;
• do statement while (expression) ;
• for (for-init-statement ; condition ; expression) statement ;
• for (for-range-declaration : for-range-initializer) statement ;
• break ;
• continue ;
Remarks
algorithm calls are generally preferable to hand-written loops.
If you want something an algorithm already does (or something very similar), the algorithm call is
clearer, often more efficient and less error prone.
If you need a loop that does something fairly simple (but would require a confusing tangle of
binders and adapters if you were using an algorithm), then just write the loop.
Examples
Range-Based For
C++11
forloops can be used to iterate over the elements of a iterator-based range, without using a
numeric index or directly accessing the iterators:
for(auto val: v)
{
std::cout << val << " ";
}
This will iterate over every element in v, with val getting the value of the current element. The
following statement:
https://riptutorial.com/ 354
for (for-range-declaration : for-range-initializer ) statement
is equivalent to:
{
auto&& __range = for-range-initializer;
auto __begin = begin-expr, __end = end-expr;
for (; __begin != __end; ++__begin) {
for-range-declaration = *__begin;
statement
}
}
C++17
{
auto&& __range = for-range-initializer;
auto __begin = begin-expr;
auto __end = end-expr; // end is allowed to be a different type than begin in C++17
for (; __begin != __end; ++__begin) {
for-range-declaration = *__begin;
statement
}
}
This change was introduced for the planned support of Ranges TS in C++20.
{
auto&& __range = v;
auto __begin = v.begin(), __end = v.end();
for (; __begin != __end; ++__begin) {
auto val = *__begin;
std::cout << val << " ";
}
}
Note that auto val declares a value type, which will be a copy of a value stored in the range (we
are copy-initializing it from the iterator as we go). If the values stored in the range are expensive to
copy, you may want to use const auto &val. You are also not required to use auto; you can use an
appropriate typename, so long as it is implicitly convertible from the range's value type.
If you need access to the iterator, range-based for cannot help you (not without some effort, at
least).
for(float &val: v)
{
std::cout << val << " ";
}
https://riptutorial.com/ 355
You could iterate on const reference if you have const container:
One would use forwarding references when the sequence iterator returns a proxy object and you
need to operate on that object in a non-const way. Note: it will most likely confuse readers of your
code.
vector<bool> v(10);
for(auto&& val: v)
{
val = true;
}
The "range" type provided to range-based for can be one of the following:
• Language arrays:
• Any type which has member functions begin() and end(), which return iterators to the
elements of the type. The standard library containers qualify, but user-defined types can be
used as well:
struct Rng
{
float arr[3];
https://riptutorial.com/ 356
};
int main()
{
Rng rng = {{0.4f, 12.5f, 16.234f}};
• Any type which has non-member begin(type) and end(type) functions which can found via
argument dependent lookup, based on type. This is useful for creating a range type without
having to modify class type itself:
namespace Mine
{
struct Rng {float arr[3];};
int main()
{
Mine::Rng rng = {{0.4f, 12.5f, 16.234f}};
For loop
A for loop executes statements in the loop body, while the loop condition is true. Before the loop
initialization statement is executed exactly once. After each cycle, the iteration execution part is
executed.
• initialization statement:This statement gets executed only once, at the beginning of the for
loop. You can enter a declaration of multiple variables of one type, such as int i = 0, a = 2,
b = 3
https://riptutorial.com/ 357
. These variables are only valid in the scope of the loop. Variables defined before the loop
with the same name are hidden during execution of the loop.
• condition: This statement gets evaluated ahead of each loop body execution, and aborts the
loop if it evaluates to false.
• iteration execution: This statement gets executed after the loop body, ahead of the next
condition evaluation, unless the for loop is aborted in the body (by break, goto, return or an
exception being thrown). You can enter multiple statements in the iteration execution part,
such as a++, b+=10, c=b+a.
/*initialization*/
while (/*condition*/)
{
// body of the loop; using 'continue' will skip to increment part below
/*iteration execution*/
}
The most common case for using a for loop is to execute statements a specific number of times.
For example, consider the following:
But if you want to use the already declared variable and not hide it, then omit the declaration part:
Notes:
• The initialization and increment statements can perform operations unrelated to the condition
statement, or nothing at all - if you wish to do so. But for readability reasons, it is best
https://riptutorial.com/ 358
practice to only perform operations directly relevant to the loop.
• A variable declared in the initialization statement is visible only inside the scope of the for
loop and is released upon termination of the loop.
• Don't forget that the variable which was declared in the initialization statement can be
modified during the loop, as well as the variable checked in the condition.
• int counter = 0 initializes the variable counter to 0. (This variable can only be used inside of
the for loop.)
• counter <= 10 is a Boolean condition that checks whether counter is less than or equal to 10.
If it is true, the loop executes. If it is false, the loop ends.
• ++counter is an increment operation that increments the value of counter by 1 ahead of the
next condition check.
// infinite loop
for (;;)
std::cout << "Never ending!\n";
// infinite loop
while (true)
std::cout << "Never ending!\n";
However, an infinite loop can still be left by using the statements break, goto, or return or by
throwing an exception.
The next common example of iterating over all elements from an STL collection (e.g., a vector)
without using the <algorithm> header is:
While loop
A while loop executes statements repeatedly until the given condition evaluates to false. This
control statement is used when it is not known, in advance, how many times a block of code is to
https://riptutorial.com/ 359
be executed.
For example, to print all the numbers from 0 up to 9, the following code can be used:
int i = 0;
while (i < 10)
{
std::cout << i << " ";
++i; // Increment counter
}
std::cout << std::endl; // End of line; "0 1 2 3 4 5 6 7 8 9" is printed to the console
C++17
while (true)
{
// Do something forever (however, you can exit the loop by calling 'break'
}
There is another variant of while loops, namely the do...while construct. See the do-while loop
example for more information.
In the condition of the for and while loops, it's also permitted to declare an object. This object will
be considered to be in scope until the end of the loop, and will persist through each iteration of the
loop:
while(std::shared_ptr<Object> p = get_object()) {
p->do_something();
}
// p is no longer in scope.
However, it is not permitted to do the same with a do...while loop; instead, declare the variable
before the loop, and (optionally) enclose both the variable and the loop within a local scope if you
want the variable to go out of scope after the loop ends:
https://riptutorial.com/ 360
//This doesn't compile
do {
s = do_something();
} while (short s > 0);
// Good
short s;
do {
s = do_something();
} while (s > 0);
This is because the statement portion of a do...while loop (the loop's body) is evaluated before the
expression portion (the while) is reached, and thus, any declaration in the expression will not be
visible during the first iteration of the loop.
Do-while loop
A do-while loop is very similar to a while loop, except that the condition is checked at the end of
each cycle, not at the start. The loop is therefore guaranteed to execute at least once.
The following code will print 0, as the condition will evaluate to false at the end of the first iteration:
int i =0;
do
{
std::cout << i;
++i; // Increment counter
}
while (i < 0);
std::cout << std::endl; // End of line; 0 is printed to the console
Note: Do not forget the semicolon at the end of while(condition);, which is needed in the do-while
construct.
In contrast to the do-while loop, the following will not print anything, because the condition
evaluates to false at the beginning of the first iteration:
int i =0;
while (i < 0)
{
std::cout << i;
++i; // Increment counter
}
std::cout << std::endl; // End of line; nothing is printed to the console
Note: A while loop can be exited without the condition becoming false by using a break, goto, or
return statement.
int i = 0;
do
{
std::cout << i;
++i; // Increment counter
https://riptutorial.com/ 361
if (i > 5)
{
break;
}
}
while (true);
std::cout << std::endl; // End of line; 0 1 2 3 4 5 is printed to the console
A trivial do-while loop is also occasionally used to write macros that require their own scope (in
which case the trailing semicolon is omitted from the macro definition and required to be provided
by the user):
Loop control statements are used to change the flow of execution from its normal sequence. When
execution leaves a scope, all automatic objects that were created in that scope are destroyed. The
break and continue are loop control statements.
1
2
3
The continue statement does not immediately exit the loop, but rather skips the rest of the loop
body and goes to the top of the loop (including checking the condition).
https://riptutorial.com/ 362
}
1 is an odd number
3 is an odd number
5 is an odd number
Because such control flow changes are sometimes difficult for humans to easily understand, break
and continue are used sparingly. More straightforward implementation are usually easier to read
and understand. For example, the first for loop with the break above might be rewritten as:
Using range-base loops, you can loop over a sub-part of a given container or other range by
generating a proxy object that qualifies for range-based for loops.
https://riptutorial.com/ 363
template<class Iterator, class Sentinel>
range_t<Iterator, Sentinel> range( Iterator b, Sentinal e ) {
return {b,e};
}
template<class Iterable>
auto range( Iterable& r ) {
using std::begin; using std::end;
return range(begin(r),end(r));
}
template<class C>
auto except_first( C& c ) {
auto r = range(c);
if (r.empty()) return r;
return r.without_front();
}
std::vector<int> v = {1,2,3,4};
2
3
4
Be aware that intermediate objects generated in the for(:range_expression) part of the for loop will
have expired by the time the for loop starts.
https://riptutorial.com/ 364
Chapter 64: Memory management
Syntax
• ::(opt) new (expression-list)(opt) new-type-id new-initializer(opt)
• ::(opt) new (expression-list)(opt) (type-id) new-initializer(opt)
• ::(opt) delete cast-expression
• ::(opt) delete [] cast-expression
• std::unique_ptr<type-id> var_name(new type-id(opt)); //C++11
• std::shared_ptr<type-id> var_name(new type-id(opt)); //C++11
• std::shared_ptr<type-id> var_name = std::make_shared<type-id>(opt); //C++11
• std::unique_ptr<type-id> var_name = std::make_unique<type-id>(opt); //C++14
Remarks
A leading :: forces the new or delete operator to be looked up in global scope, overriding any
overloaded class-specific new or delete operators.
The optional arguments following the new keyword are usually used to call placement new, but can
also be used to pass additional information to the allocator, such as a tag requesting that memory
be allocated from a chosen pool.
The type allocated is usually explicitly specified, e.g., new Foo, but can also be written as auto
(since C++11) or decltype(auto) (since C++14) to deduce it from the initializer.
Initialization of the object allocated occurs according to the same rules as initialization of local
variables. In particular, the object will be default-initialized if the initializer iso omitted, and when
dynamically allocating a scalar type or an array of scalar type, there is no guarantee that the
memory will be zeroed out.
using IA = int[4];
int* pIA = new IA;
delete[] pIA; // right
// delete pIA; // wrong
Examples
Stack
The stack is a small region of memory into which temporary values are placed during execution.
Allocating data into the stack is very fast compared to heap allocation, as all the memory has
already been assigned for this purpose.
https://riptutorial.com/ 365
int main() {
int a = 0; //Stored on the stack
return a;
}
The stack is named because chains of function calls will have their temporary memory 'stacked' on
top of each other, each one using a separate small section of memory.
float bar() {
//f will be placed on the stack after anything else
float f = 2;
return f;
}
double foo() {
//d will be placed just after anything within main()
double d = bar();
return d;
}
int main() {
//The stack has no user variables stored in it until foo() is called
return (int)foo();
}
Data stored on the stack is only valid so long as the scope that allocated the variable is still active.
int* pA = nullptr;
void foo() {
int b = *pA;
pA = &b;
}
int main() {
int a = 5;
pA = &a;
foo();
//Undefined behavior, the value pointed to by pA is no longer in scope
a = *pA;
}
The term 'heap' is a general computing term meaning an area of memory from which portions can
be allocated and deallocated independently of the memory provided by the stack.
In C++ the Standard refers to this area as the Free Store which is considered a more accurate
term.
Areas of memory allocated from the Free Store may live longer than the original scope in which it
was allocated. Data too large to be stored on the stack may also be allocated from the Free Store.
Raw memory can be allocated and deallocated by the new and delete keywords.
https://riptutorial.com/ 366
float *foo = nullptr;
{
*foo = new float; // Allocates memory for a float
float bar; // Stack allocated
} // End lifetime of bar, while foo still alive
delete foo; // Deletes the memory for the float at pF, invalidating the pointer
foo = nullptr; // Setting the pointer to nullptr after delete is often considered good
practice
It's also possible to allocate fixed size arrays with new and delete, with a slightly different syntax.
Array allocation is not compatible with non-array allocation, and mixing the two will lead to heap
corruption. Allocating an array also allocates memory to track the size of the array for later deletion
in an implementation-defined way.
When using new and delete instead malloc and free, the constructor and destructor will get
executed (Similar to stack based objects). This is why new and delete are prefered over malloc
and free.
struct ComplexType {
int a = 0;
C++11
From C++11 on, the use of smart pointers is recommended for indicating ownership.
C++14
C++14 added std::make_unique to the STL, changing the recommendation to favor std::make_unique
or std::make_shared instead of using naked new and delete.
Placement new
There are situations when we don't want to rely upon Free Store for allocating memory and we
want to use custom memory allocations using new.
For these situations we can use Placement New, where we can tell `new' operator to allocate
memory from a pre-allocated memory location
https://riptutorial.com/ 367
For example
int a4byteInteger;
In this example, the memory pointed by a4byteChar is 4 byte allocated to 'stack' via integer variable
a4byteInteger.
The benefit of this kind of memory allocation is the fact that programmers control the allocation. In
the example above, since a4byteInteger is allocated on stack, we don't need to make an explicit
call to 'delete a4byteChar`.
Same behavior can be achieved for dynamic allocated memory also. For example
In this case, the memory pointer by a8byteChar will be referring to dynamic memory allocated by
a8byteDynamicInteger. In this case however, we need to explicitly calldelete a8byteDynamicInteger to
release the memory
struct ComplexType {
int a;
ComplexType() : a(0) {}
~ComplexType() {}
};
int main() {
char* dynArray = new char[256];
new((void*)localArray) ComplexType();
return 0;
}
https://riptutorial.com/ 368
management
https://riptutorial.com/ 369
Chapter 65: Metaprogramming
Introduction
In C++ Metaprogramming refers to the use of macros or templates to generate code at compile-
time.
In general, macros are frowned upon in this role and templates are preferred, although they are
not as generic.
Remarks
Metaprogramming (or more specifically, Template Metaprogramming) is the practice of using
templates to create constants, functions, or data structures at compile-time. This allows
computations to be performed once at compile time rather than at each run time.
Examples
Calculating Factorials
#include <iostream>
template<>
struct factorial<0>
{
enum { value = 1 };
};
int main()
{
std::cout << factorial<7>::value << std::endl; // prints "5040"
}
https://riptutorial.com/ 370
convention, template metafunctions are evaluated by checking a particular member, either ::type
for metafunctions that result in types, or ::value for metafunctions that generate values.
In the above code, we evaluate the factorial metafunction by instantiating the template with the
parameters we want to pass, and using ::value to get the result of the evaluation.
The metafunction itself relies on recursively instantiating the same metafunction with smaller
values. The factorial<0> specialization represents the terminating condition. Template
metaprogramming has most of the restrictions of a functional programming language, so recursion
is the primary "looping" construct.
Since template metafunctions execute at compile time, their results can be used in contexts that
require compile-time values. For example:
int my_array[factorial<5>::value];
Automatic arrays must have a compile-time defined size. And the result of a metafunction is a
compile-time constant, so it can be used here.
Limitation: Most of the compilers won't allow recursion depth beyond a limit. For example, g++
compiler by default limits recursion depeth to 256 levels. In case of g++, programmer can set
recursion depth using -ftemplate-depth-X option.
C++11
Since C++11, the std::integral_constant template can be used for this kind of template
computation:
#include <iostream>
#include <type_traits>
template<>
struct factorial<0> :
std::integral_constant<long long, 1> {};
int main()
{
std::cout << factorial<7>::value << std::endl; // prints "5040"
}
#include <iostream>
https://riptutorial.com/ 371
int main()
{
char test[factorial(3)];
std::cout << factorial(7) << '\n';
}
The body of factorial() is written as a single statement because in C++11 constexpr functions can
only use a quite limited subset of the language.
C++14
Since C++14, many restrictions for constexpr functions have been dropped and they can now be
written much more conveniently:
Or even:
C++17
#include <iostream>
#include <utility>
int main() {
std::cout << factorial<int, 5>::value << std::endl;
}
https://riptutorial.com/ 372
Often, we need to perform an operation over every element in a variadic template parameter pack.
There are many ways to do this, and the solutions get easier to read and write with C++17.
Suppose we simply want to print every element in a pack. The simplest solution is to recurse:
C++11
print_all(os, rest...);
}
We could instead use the expander trick, to perform all the streaming in a single function. This has
the advantage of not needing a second overload, but has the disadvantage of less than stellar
readability:
C++11
C++17
With C++17, we get two powerful new tools in our arsenal for solving this problem. The first is a
fold-expression:
And the second is if constexpr, which allows us to write our original recursive solution in a single
function:
https://riptutorial.com/ 373
print_all(os, rest...);
}
}
template<std::size_t N>
using make_index_sequence = make_integer_sequence<std::size_t, N>;
While this comes standard in C++14, this can be implemented using C++11 tools.
We can use this tool to call a function with a std::tuple of arguments (standardized in C++17 as
std::apply):
namespace detail {
template <class F, class Tuple, std::size_t... Is>
decltype(auto) apply_impl(F&& f, Tuple&& tpl, std::index_sequence<Is...> ) {
return std::forward<F>(f)(std::get<Is>(std::forward<Tuple>(tpl))...);
}
}
Tag Dispatching
https://riptutorial.com/ 374
implement std::advance(), we can dispatch on the iterator category:
namespace details {
template <class RAIter, class Distance>
void advance(RAIter& it, Distance n, std::random_access_iterator_tag) {
it += n;
}
Tag dispatching can give you code that's much easier to read than the equivalents using SFINAE
and enable_if.
Note: while C++17's if constexpr may simplify the implementation of advance in particular, it is not
suitable for open implementations unlike tag dispatching.
It is possible to detect whether an operator or function can be called on a type. To test if a class
has an overload of std::hash, one can do this:
https://riptutorial.com/ 375
#include <functional> // for std::hash
#include <type_traits> // for std::false_type and std::true_type
#include <utility> // for std::declval
template<class T>
struct has_hash<T, decltype(std::hash<T>()(std::declval<T>()), void())>
: std::true_type
{};
C++17
template<class T>
struct has_hash<T, std::void_t< decltype(std::hash<T>()(std::declval<T>())) > >
: std::true_type
{};
For detecting if an operator, such as operator< is defined, the syntax is almost the same:
template<class T>
struct has_less_than<T, decltype(std::declval<T>() < std::declval<T>(), void())>
: std::true_type
{};
These can be used to use a std::unordered_map<T> if T has an overload for std::hash, but otherwise
attempt to use a std::map<T>:
https://riptutorial.com/ 376
Calculating power with C++11 (and higher)
With C++11 and higher calculations at compile time can be much easier. For example calculating
the power of a given number at compile time will be following:
Keyword constexpr is responsible for calculating function in compilation time, then and only then,
when all the requirements for this will be met (see more at constexpr keyword reference) for
example all the arguments must be known at compile time.
Note: In C++11 constexpr function must compose only from one return statement.
Advantages: Comparing this to the standard way of compile time calculation, this method is also
useful for runtime calculations. It means, that if the arguments of the function are not known at the
compilation time (e.g. value and power are given as input via user), then function is run in a
compilation time, so there's no need to duplicate a code (as we would be forced in older standards
of C++).
E.g.
void useExample() {
constexpr int compileTimeCalculated = calculatePower(3, 3); // computes at compile time,
// as both arguments are known at compilation time
// and used for a constant expression.
int value;
std::cin >> value;
int runtimeCalculated = calculatePower(value, 3); // runtime calculated,
// because value is known only at runtime.
}
C++17
Another way to calculate power at compile time can make use of fold expression as follows:
#include <iostream>
#include <utility>
int main() {
std::cout << power<int, 4, 2>::value << std::endl;
}
https://riptutorial.com/ 377
Manual distinction of types when given any type T
When implementing SFINAE using std::enable_if, it is often useful to have access to helper
templates that determines if a given type T matches a set of criteria.
To help us with that, the standard already provides two types analog to true and false which are
std::true_type and std::false_type.
The following example show how to detect if a type T is a pointer or not, the is_pointer template
mimic the behavior of the standard std::is_pointer helper:
There are three steps in the above code (sometimes you only need two):
1. The first declaration of is_pointer_ is the default case, and inherits from std::false_type. The
default case should always inherit from std::false_type since it is analogous to a "false
condition".
2. The second declaration specialize the is_pointer_ template for pointer T* without caring
about what T is really. This version inherits from std::true_type.
3. The third declaration (the real one) simply remove any unnecessary information from T (in
this case we remove const and volatile qualifiers) and then fall backs to one of the two
previous declarations.
• Use ::value, e.g. is_pointer<int>::value – value is a static class member of type bool
inherited from std::true_type or std::false_type;
• Construct an object of this type, e.g. is_pointer<int>{} – This works because std::is_pointer
inherits its default constructor from std::true_type or std::false_type (which have constexpr
constructors) and both std::true_type and std::false_type have constexpr conversion
operators to bool.
It is a good habit to provides "helper helper templates" that let you directly access the value:
C++17
In C++17 and above, most helper templates already provide a _v version, e.g.:
https://riptutorial.com/ 378
template< class T > constexpr bool is_pointer_v = is_pointer<T>::value;
template< class T > constexpr bool is_reference_v = is_reference<T>::value;
If-then-else
C++11
The type std::conditional in the standard library header <type_traits> can select one type or the
other, based on a compile-time boolean value:
template<typename T>
struct ValueOrPointer
{
typename std::conditional<(sizeof(T) > sizeof(void*)), T*, T>::type vop;
};
This struct contains a pointer to T if T is larger than the size of a pointer, or T itself if it is smaller or
equal to a pointer's size. Therefore sizeof(ValueOrPointer) will always be <= sizeof(void*).
C++11
It's possible to write a generic function (for example min) which accepts various numerical types
and arbitrary argument count by template meta-programming. This function declares a min for two
arguments and recursively for more.
https://riptutorial.com/ 379
Chapter 66: More undefined behaviors in C++
Introduction
More examples on how C++ can go wrong.
Examples
Referring to non-static members in initializer lists
Referring to non-static members in initializer lists before the constructor has started executing can
result in undefined behavior. This results since not all members are constructed at this time. From
the standard draft:
§12.7.1: For an object with a non-trivial constructor, referring to any non-static member
or base class of the object before the constructor begins execution results in undefined
behavior.
Example
struct W { int j; };
struct X : public virtual W { };
struct Y {
int *p;
X x;
Y() : p(&x.j) { // undefined, x is not yet constructed
}
};
https://riptutorial.com/ 380
Chapter 67: Move Semantics
Examples
Move semantics
Move semantics are a way of moving one object to another in C++. For this, we empty the old
object and place everything it had in the new object.
For this, we must understand what an rvalue reference is. An rvalue reference (T&& where T is the
object type) is not much different than a normal reference (T&, now called lvalue references). But
they act as 2 different types, and so, we can make constructors or functions that take one type or
the other, which will be necessary when dealing with move semantics.
The reason why we need two different types is to specify two different behaviors. Lvalue reference
constructors are related to copying, while rvalue reference constructors are related to moving.
To move an object, we will use std::move(obj). This function returns an rvalue reference to the
object, so that we can steal the data from that object into a new one. There are several ways of
doing this which are discussed below.
Important to note is that the use of std::move creates just an rvalue reference. In other words the
statement std::move(obj) does not change the content of obj, while auto obj2 = std::move(obj)
(possibly) does.
Move constructor
class A {
public:
int a;
int b;
A(const A &other) {
this->a = other.a;
this->b = other.b;
}
};
To create a copy constructor, that is, to make a function that copies an object and creates a new
one, we normally would choose the syntax shown above, we would have a constructor for A that
takes an reference to another object of type A, and we would copy the object manually inside the
method.
Alternatively, we could have written A(const A &) = default; which automatically copies over all
members, making use of its copy constructor.
https://riptutorial.com/ 381
To create a move constructor, however, we will be taking an rvalue reference instead of an lvalue
reference, like here.
class Wallet {
public:
int nrOfDollars;
Wallet(Wallet &&other) {
this->nrOfDollars = other.nrOfDollars;
other.nrOfDollars = 0;
}
};
Please notice that we set the old values to zero. The default move constructor (Wallet(Wallet&&) =
default;) copies the value of nrOfDollars, as it is a POD.
As move semantics are designed to allow 'stealing' state from the original instance, it is important
to consider how the original instance should look like after this stealing. In this case, if we would
not change the value to zero we would have doubled the amount of dollars into play.
Wallet a;
a.nrOfDollars = 1;
Wallet b (std::move(a)); //calling B(B&& other);
std::cout << a.nrOfDollars << std::endl; //0
std::cout << b.nrOfDollars << std::endl; //1
While the above is a simple example, it shows what the move constructor is intended to do. It
becomes more useful in more complex cases, such as when resource management is involved.
HeapHelper<T>* h_helper;
StackHelper<T> s_helper;
// ...
public:
// Default constructor & Rule of Five.
OperationsManager() : h_helper(new HeapHelper<T>) {}
OperationsManager(const MyType& other)
: h_helper(new HeapHelper<T>(*other.h_helper)), s_helper(other.s_helper) {}
MyType& operator=(MyType copy) {
swap(*this, copy);
return *this;
}
https://riptutorial.com/ 382
~OperationsManager() {
if (h_helper) { delete h_helper; }
}
// Copy/move helper.
friend void swap(MyType& left, MyType& right) noexcept {
std::swap(left.h_helper, right.h_helper);
std::swap(left.s_helper, right.s_helper);
}
};
Move assignment
Similarly to how we can assign a value to an object with an lvalue reference, copying it, we can
also move the values from an object to another without constructing a new one. We call this move
assignment. We move the values from one object to another existing object.
For this, we will have to overload operator =, not so that it takes an lvalue reference, like in copy
assignment, but so that it takes an rvalue reference.
class A {
int a;
A& operator= (A&& other) {
this->a = other.a;
other.a = 0;
return *this;
}
};
This is the typical syntax to define move assignment. We overload operator = so that we can feed
it an rvalue reference and it can assign it to another object.
A a;
a.a = 1;
A b;
b = std::move(a); //calling A& operator= (A&& other)
std::cout << a.a << std::endl; //0
https://riptutorial.com/ 383
std::cout << b.a << std::endl; //1
C++11 introduced core language and standard library support for moving an object. The idea is
that when an object o is a temporary and one wants a logical copy, then its safe to just pilfer o's
resources, such as a dynamically allocated buffer, leaving o logically empty but still destructible
and copyable.
• the rvalue reference type builder &&, e.g., std::string&& is an rvalue reference to a
std::string, indicating that that referred to object is a temporary whose resources can just be
pilfered (i.e. moved)
• special support for a move constructor T( T&& ), which is supposed to efficiently move
resources from the specified other object, instead of actually copying those resources, and
• special support for a move assignment operator auto operator=(T&&) -> T&, which also is
supposed to move from the source.
The standard library support is mainly the std::move function template from the <utility> header.
This function produces an rvalue reference to the specified object, indicating that it can be moved
from, just as if it were a temporary.
For a container actual copying is typically of O(n) complexity, where n is the number of items in the
container, while moving is O(1), constant time. And for an algorithm that logically copies that
container n times, this can reduce the complexity from the usually impractical O(n²) to just linear
O(n).
In his article “Containers That Never Change” in Dr. Dobbs Journal in September 19 2013, Andrew
Koenig presented an interesting example of algorithmic inefficiency when using a style of
programming where variables are immutable after initialization. With this style loops are generally
expressed using recursion. And for some algorithms such as generating a Collatz sequence, the
recursion requires logically copying a container:
namespace my {
template< class Item >
using Vector_ = /* E.g. std::vector<Item> */;
https://riptutorial.com/ 384
{
auto result{ v };
result.push_back( x );
return result;
}
#include <iostream>
using namespace std;
auto main() -> int
{
for( int const x : my::collatz( 42 ) )
{
cout << x << ' ';
}
cout << '\n';
}
Output:
42 21 64 32 16 8 4 2
The number of item copy operations due to copying of the vectors is here roughly O(n²), since it's
the sum 1 + 2 + 3 + ... n.
In concrete numbers, with g++ and Visual C++ compilers the above invocation of collatz(42)
resulted in a Collatz sequence of 8 items and 36 item copy operations (8*7/2 = 28, plus some) in
vector copy constructor calls.
All of these item copy operations can be removed by simply moving vectors whose values are not
needed anymore. To do this it's necessary to remove const and reference for the vector type
arguments, passing the vectors by value. The function returns are already automatically optimized.
https://riptutorial.com/ 385
For the calls where vectors are passed, and not used again further on in the function, just apply
std::move to move those buffers rather than actually copying them:
using std::move;
Here, with g++ and Visual C++ compilers, the number of item copy operations due to vector copy
constructor invocations, was exactly 0.
The algorithm is necessarily still O(n) in the length of the Collatz sequence produced, but this is a
quite dramatic improvement: O(n²) → O(n).
With some language support one could perhaps use moving and still express and enforce the
immutability of a variable between its initialization and final move, after which any use of that
variable should be an error. Alas, as of C++14 C++ does not support that. For loop-free code the
no use after move can be enforced via a re-declaration of the relevant name as an incomplete
struct, as with struct result; above, but this is ugly and not likely to be understood by other
programmers; also the diagnostics can be quite misleading.
https://riptutorial.com/ 386
Summing up, the C++ language and library support for moving allows drastic improvements in
algorithm complexity, but due the support's incompleteness, at the cost of forsaking the code
correctness guarantees and code clarity that const can provide.
For completeness, the instrumented vector class used to measure the number of item copy operations due to copy
constructor invocations:
vector<Item> items_;
public:
static auto n() -> int { return n_copy_ops(); }
Copy_tracking_vector(){}
int main() {
// initialize vec1 with 1, 2, 3, 4 and vec2 as an empty vector
std::vector<int> vec1{1, 2, 3, 4};
std::vector<int> vec2;
https://riptutorial.com/ 387
// The following line will print a new line
print(vec2);
int main() {
// initialize vec with 1, 2, 3, 4
std::vector<int> vec{1, 2, 3, 4};
https://riptutorial.com/ 388
Chapter 68: mutable keyword
Examples
non-static class member modifier
mutablemodifier in this context is used to indicate that a data field of a const object may be
modified without affecting the externally-visible state of the object.
If you are thinking about caching a result of expensive computation, you should probably use this
keyword.
If you have a lock (for example, std::unique_lock) data field which is locked and unlocked inside a
const method, this keyword is also what you could use.
You should not use this keyword to break logical const-ness of an object.
class pi_calculator {
public:
double get_pi() const {
if (pi_calculated) {
return pi;
} else {
double new_pi = 0;
for (int i = 0; i < 1000000000; ++i) {
// some calculation to refine new_pi
}
// note: if pi and pi_calculated were not mutable, we would get an error from a
compiler
// because in a const method we can not change a non-mutable field
pi = new_pi;
pi_calculated = true;
return pi;
}
}
private:
mutable bool pi_calculated = false;
mutable double pi = 0;
};
mutable lambdas
By default, the implicit operator() of a lambda is const. This disallows performing non-const
operations on the lambda. In order to allow modifying members, a lambda may be marked mutable,
which makes the implicit operator() non-const:
int a = 0;
https://riptutorial.com/ 389
return a++; // error: operator() is const
// cannot modify members
};
good_counter(); // 0
good_counter(); // 1
good_counter(); // 2
https://riptutorial.com/ 390
Chapter 69: Mutexes
Remarks
If you want to use RWLock, you will find that there are two options.
It is std::shared_mutex and shared_timed_mutex.
you may think std::shared_timed_mutex is just the version 'std::shared_mutex + time method'.
class shared_mutex
{
public:
typedef _Smtx_t * native_handle_type;
shared_mutex() _NOEXCEPT
: _Myhandle(0)
{ // default construct
}
~shared_mutex() _NOEXCEPT
{ // destroy the object
}
https://riptutorial.com/ 391
_Smtx_lock_shared(&_Myhandle);
}
You can see that std::shared_mutex is implemented in Windows Slim Reader/Write Locks(
https://msdn.microsoft.com/ko-kr/library/windows/desktop/aa904937(v=vs.85).aspx)
https://riptutorial.com/ 392
The code below is MSVC14.1 implementation of
std::shared_timed_mutex.
class shared_timed_mutex
{
typedef unsigned int _Read_cnt_t;
static constexpr _Read_cnt_t _Max_readers = _Read_cnt_t(-1);
public:
shared_timed_mutex() _NOEXCEPT
: _Mymtx(), _Read_queue(), _Write_queue(),
_Readers(0), _Writing(false)
{ // default construct
}
~shared_timed_mutex() _NOEXCEPT
{ // destroy the object
}
void lock()
{ // lock exclusive
unique_lock<mutex> _Lock(_Mymtx);
while (_Writing)
_Write_queue.wait(_Lock);
_Writing = true;
while (0 < _Readers)
_Read_queue.wait(_Lock); // wait for writing, no readers
}
bool try_lock()
{ // try to lock exclusive
lock_guard<mutex> _Lock(_Mymtx);
if (_Writing || 0 < _Readers)
return (false);
else
{ // set writing, no readers
_Writing = true;
return (true);
}
}
template<class _Rep,
class _Period>
bool try_lock_for(
const chrono::duration<_Rep, _Period>& _Rel_time)
{ // try to lock for duration
return (try_lock_until(chrono::steady_clock::now() + _Rel_time));
}
template<class _Clock,
class _Duration>
bool try_lock_until(
const chrono::time_point<_Clock, _Duration>& _Abs_time)
{ // try to lock until time point
auto _Not_writing = [this] { return (!_Writing); };
auto _Zero_readers = [this] { return (_Readers == 0); };
unique_lock<mutex> _Lock(_Mymtx);
https://riptutorial.com/ 393
_Writing = true;
return (true);
}
void unlock()
{ // unlock exclusive
{ // unlock before notifying, for efficiency
lock_guard<mutex> _Lock(_Mymtx);
_Writing = false;
}
_Write_queue.notify_all();
}
void lock_shared()
{ // lock non-exclusive
unique_lock<mutex> _Lock(_Mymtx);
while (_Writing || _Readers == _Max_readers)
_Write_queue.wait(_Lock);
++_Readers;
}
bool try_lock_shared()
{ // try to lock non-exclusive
lock_guard<mutex> _Lock(_Mymtx);
if (_Writing || _Readers == _Max_readers)
return (false);
else
{ // count another reader
++_Readers;
return (true);
}
}
template<class _Rep,
class _Period>
bool try_lock_shared_for(
const chrono::duration<_Rep, _Period>& _Rel_time)
{ // try to lock non-exclusive for relative time
return (try_lock_shared_until(_Rel_time
+ chrono::steady_clock::now()));
}
template<class _Time>
bool _Try_lock_shared_until(_Time _Abs_time)
{ // try to lock non-exclusive until absolute time
auto _Can_acquire = [this] {
return (!_Writing && _Readers < _Max_readers); };
unique_lock<mutex> _Lock(_Mymtx);
https://riptutorial.com/ 394
if (!_Write_queue.wait_until(_Lock, _Abs_time, _Can_acquire))
return (false);
++_Readers;
return (true);
}
template<class _Clock,
class _Duration>
bool try_lock_shared_until(
const chrono::time_point<_Clock, _Duration>& _Abs_time)
{ // try to lock non-exclusive until absolute time
return (_Try_lock_shared_until(_Abs_time));
}
void unlock_shared()
{ // unlock non-exclusive
_Read_cnt_t _Local_readers;
bool _Local_writing;
~stl_condition_variable_win7() = delete;
stl_condition_variable_win7(const stl_condition_variable_win7&) = delete;
stl_condition_variable_win7& operator=(const stl_condition_variable_win7&) = delete;
https://riptutorial.com/ 395
virtual void wait(stl_critical_section_interface *lock) override
{
if (!stl_condition_variable_win7::wait_for(lock, INFINITE))
std::terminate();
}
private:
CONDITION_VARIABLE m_condition_variable;
};
void useSTLSharedMutex()
{
std::shared_mutex shared_mtx_lock;
https://riptutorial.com/ 396
std::vector<std::thread> readThreads;
std::vector<std::thread> writeThreads;
std::list<int> data = { 0 };
volatile bool exit = false;
std::atomic<int> readProcessedCnt(0);
std::atomic<int> writeProcessedCnt(0);
while (true)
{
shared_mtx_lock.lock_shared();
mydata.push_back(data.back());
++localProcessCnt;
shared_mtx_lock.unlock_shared();
if (exit)
break;
}
std::atomic_fetch_add(&readProcessedCnt, localProcessCnt);
}));
int localProcessCnt = 0;
while (true)
{
shared_mtx_lock.lock();
data.push_back(rand() % 100);
++localProcessCnt;
shared_mtx_lock.unlock();
if (exit)
break;
}
std::atomic_fetch_add(&writeProcessedCnt, localProcessCnt);
}));
}
std::this_thread::sleep_for(std::chrono::milliseconds(MAIN_WAIT_MILLISECONDS));
exit = true;
https://riptutorial.com/ 397
for (auto &r : readThreads)
r.join();
void useSTLSharedTimedMutex()
{
std::shared_timed_mutex shared_mtx_lock;
std::vector<std::thread> readThreads;
std::vector<std::thread> writeThreads;
std::list<int> data = { 0 };
volatile bool exit = false;
std::atomic<int> readProcessedCnt(0);
std::atomic<int> writeProcessedCnt(0);
while (true)
{
shared_mtx_lock.lock_shared();
mydata.push_back(data.back());
++localProcessCnt;
shared_mtx_lock.unlock_shared();
if (exit)
break;
}
std::atomic_fetch_add(&readProcessedCnt, localProcessCnt);
}));
int localProcessCnt = 0;
while (true)
{
shared_mtx_lock.lock();
data.push_back(rand() % 100);
++localProcessCnt;
https://riptutorial.com/ 398
shared_mtx_lock.unlock();
if (exit)
break;
}
std::atomic_fetch_add(&writeProcessedCnt, localProcessCnt);
}));
}
std::this_thread::sleep_for(std::chrono::milliseconds(MAIN_WAIT_MILLISECONDS));
exit = true;
Examples
std::unique_lock, std::shared_lock, std::lock_guard
Used for the RAII style acquiring of try locks, timed try locks and recursive locks.
std::shared_lock allows for shared ownership of mutexes. Several threads can hold
std::shared_locks on a std::shared_mutex. Available from C++ 14.
#include <unordered_map>
#include <mutex>
#include <shared_mutex>
#include <thread>
#include <string>
#include <iostream>
class PhoneBook {
public:
std::string getPhoneNo( const std::string & name )
{
std::shared_lock<std::shared_timed_mutex> l(_protect);
auto it = _phonebook.find( name );
if ( it != _phonebook.end() )
return (*it).second;
return "";
https://riptutorial.com/ 399
}
void addPhoneNo ( const std::string & name, const std::string & phone )
{
std::unique_lock<std::shared_timed_mutex> l(_protect);
_phonebook[name] = phone;
}
std::shared_timed_mutex _protect;
std::unordered_map<std::string,std::string> _phonebook;
};
When creating a std::unique_lock, there are three different locking strategies to choose from:
std::try_to_lock, std::defer_lock and std::adopt_lock
{
std::atomic_int temp {0};
std::mutex _mutex;
std::thread t( [&](){
if(lock.owns_lock()){
//do something
temp=0;
}
}
});
while ( true )
{
std::this_thread::sleep_for(std::chrono::seconds(1));
std::unique_lock<std::mutex> lock( _mutex, std::try_to_lock);
if(lock.owns_lock()){
if (temp < INT_MAX){
++temp;
}
std::cout << temp << std::endl;
}
}
}
2. std::defer_lock allows for creating a lock structure without acquiring the lock. When locking
more than one mutex, there is a window of opportunity for a deadlock if two function callers
try to acquire the locks at the same time:
{
std::unique_lock<std::mutex> lock1(_mutex1, std::defer_lock);
std::unique_lock<std::mutex> lock2(_mutex2, std::defer_lock);
lock1.lock()
https://riptutorial.com/ 400
lock2.lock(); // deadlock here
std::cout << "Locked! << std::endl;
//...
}
With the following code, whatever happens in the function, the locks are acquired and released in
appropriate order:
{
std::unique_lock<std::mutex> lock1(_mutex1, std::defer_lock);
std::unique_lock<std::mutex> lock2(_mutex2, std::defer_lock);
std::lock(lock1,lock2); // no deadlock possible
std::cout << "Locked! << std::endl;
//...
3. std::adopt_lock does not attempt to lock a second time if the calling thread currently owns
the lock.
{
std::unique_lock<std::mutex> lock1(_mutex1, std::adopt_lock);
std::unique_lock<std::mutex> lock2(_mutex2, std::adopt_lock);
std::cout << "Locked! << std::endl;
//...
}
Something to keep in mind is that std::adopt_lock is not a substitute for recursive mutex usage.
When the lock goes out of scope the mutex is released.
std::mutex
std::mutex is a simple, non-recursive synchronization structure that is used to protect data which is
accessed by multiple threads.
std::atomic_int temp{0};
std::mutex _mutex;
std::thread t( [&](){
temp=0;
}
});
while ( true )
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
std::unique_lock<std::mutex> lock( _mutex, std::try_to_lock);
if ( temp < INT_MAX )
temp++;
https://riptutorial.com/ 401
cout << temp << endl;
std::scoped_lock provides RAII style semantics for owning one more mutexes, combined with the
lock avoidance algorithms used by std::lock. When std::scoped_lock is destroyed, mutexes are
released in the reverse order from which they where acquired.
{
std::scoped_lock lock{_mutex1,_mutex2};
//do something
}
Mutex Types
std::lock
std::lock uses deadlock avoidance algorithms to lock one or more mutexes. If an exception is
thrown during a call to lock multiple objects, std::lock unlocks the successfully locked objects
before re-throwing the exception.
std::lock(_mutex1, _mutex2);
https://riptutorial.com/ 402
Chapter 70: Namespaces
Introduction
Used to prevent name collisions when using multiple libraries, a namespace is a declarative prefix
for functions, classes, types, etc.
Syntax
• namespace identifier(opt) { declaration-seq }
• inline namespace identifier(opt) { declaration-seq } /* since C++11 */
• inline(opt) namespace attribute-specifier-seq identifier(opt) { declaration-seq } /* since C++17
*/
• namespace enclosing-namespace-specifier :: identifier { declaration-seq } /* since C++17 */
• namespace identifier = qualified-namespace-specifier;
• using namespace nested-name-specifier(opt) namespace-name;
• attribute-specifier-seq using namespace nested-name-specifier(opt) namespace-name; /*
since C++11 */
Remarks
The keyword namespace has three different meanings depending on context:
3. When preceded by using and followed by a namespace name, it forms a using directive,
which allows names in the given namespace to be found by unqualified name lookup (but
does not redeclare those names in the current scope). A using-directive cannot occur at
class scope.
using namespace std; is discouraged. Why? Because namespace std is huge! This means that there
is a high chance that names will collide:
//Really bad!
using namespace std;
//Calls pow
pow(5.0, 2.0); //Error! There is already a pow function in namespace std with the same
signature,
//so the call is ambiguous
https://riptutorial.com/ 403
Examples
What are namespaces?
A C++ namespace is a collection of C++ entities (functions, classes, variables), whose names are
prefixed by the name of the namespace. When writing code within a namespace, named entities
belonging to that namespace need not be prefixed with the namespace name, but entities outside
of it must use the fully qualified name. The fully qualified name has the format
<namespace>::<entity>. Example:
namespace Example
{
const int test = 5;
const int test3 = test + 3; //Fails; `test` not found outside of namespace.
Namespaces are useful for grouping related definitions together. Take the analogy of a shopping
mall. Generally a shopping mall is split up into several stores, each store selling items from a
specific category. One store might sell electronics, while another store might sell shoes. These
logical separations in store types help the shoppers find the items they're looking for. Namespaces
help c++ programmers, like shoppers, find the functions, classes, and variables they're looking for
by organizing them in a logical manner. Example:
namespace Electronics
{
int TotalStock;
class Headphones
{
// Description of a Headphone (color, brand, model number, etc.)
};
class Television
{
// Description of a Television (color, brand, model number, etc.)
};
}
namespace Shoes
{
int TotalStock;
class Sandal
{
// Description of a Sandal (color, brand, model number, etc.)
};
class Slipper
{
// Description of a Slipper (color, brand, model number, etc.)
};
}
https://riptutorial.com/ 404
There is a single namespace predefined, which is the global namespace that has no name, but
can be denoted by ::. Example:
void bar() {
// defined in global namespace
}
namespace foo {
void bar() {
// defined in namespace foo
}
void barbar() {
bar(); // calls foo::bar()
::bar(); // calls bar() defined in global namespace
}
}
Making namespaces
To call bar, you have to specify the namespace first, followed by the scope resolution operator :::
Foo::bar();
namespace A
{
namespace B
{
namespace C
{
void bar() {}
}
}
}
C++17
namespace A::B::C
{
void bar() {}
}
https://riptutorial.com/ 405
Extending namespaces
A useful feature of namespaces is that you can expand them (add members to it).
namespace Foo
{
void bar() {}
}
namespace Foo
{
void bar2() {}
}
Using directive
The keyword 'using' has three flavors. Combined with keyword 'namespace' you write a 'using
directive':
If you don't want to write Foo:: in front of every stuff in the namespace Foo, you can use using
namespace Foo; to import every single thing out of Foo.
namespace Foo
{
void bar() {}
void baz() {}
}
//Import Foo
using namespace Foo;
bar(); //OK
baz(); //OK
It is also possible to import selected entities in a namespace rather than the whole namespace:
using Foo::bar;
bar(); //OK, was specifically imported
baz(); // Not OK, was not imported
A word of caution: using namespaces in header files is seen as bad style in most cases. If this is
done, the namespace is imported in every file that includes the header. Since there is no way of
"un-using" a namespace, this can lead to namespace pollution (more or unexpected symbols in
the global namespace) or, worse, conflicts. See this example for an illustration of the problem:
https://riptutorial.com/ 406
}
When calling a function without an explicit namespace qualifier, the compiler can choose to call a
function within a namespace if one of the parameter types to that function is also in that
namespace. This is called "Argument Dependent Lookup", or ADL:
namespace Test
{
int call(int i);
Test::SomeClass data;
call_too(data); //Succeeds
callfails because none of its parameter types come from the Test namespace. call_too works
because SomeClass is a member of Test and therefore it qualifies for ADL rules.
ADL does not occur if normal unqualified lookup finds a class member, a function that has been
declared at block scope, or something that is not of function type. For example:
void foo();
namespace N {
struct X {};
void foo(X ) { std::cout << '1'; }
void qux(X ) { std::cout << '2'; }
https://riptutorial.com/ 407
}
struct C {
void foo() {}
void bar() {
foo(N::X{}); // error: ADL is disabled and C::foo() takes no arguments
}
};
void bar() {
extern void foo(); // redeclares ::foo
foo(N::X{}); // error: ADL is disabled and ::foo() doesn't take any arguments
}
int qux;
void baz() {
qux(N::X{}); // error: variable declaration disables ADL for "qux"
}
Inline namespace
C++11
inline namespace includes the content of the inlined namespace in the enclosing namespace, so
namespace Outer
{
inline namespace Inner
{
void foo();
}
}
is mostly equivalent to
namespace Outer
{
namespace Inner
{
void foo();
}
using Inner::foo;
}
but element from Outer::Inner:: and those associated into Outer:: are identical.
So following is equivalent
Outer::foo();
Outer::Inner::foo();
The alternative using namespace Inner; would not be equivalent for some tricky parts as template
https://riptutorial.com/ 408
specialization:
For
class MyCustomType;
namespace Outer
{
template <>
void foo<MyCustomType>() { std::cout << "Specialization"; }
}
// outer.h
// include guard omitted for simplification
namespace Outer
{
inline namespace Inner
{
template <typename T>
void foo() { std::cout << "Generic"; }
}
}
// outer.h
// include guard omitted for simplification
namespace Outer
{
namespace Inner
{
template <typename T>
void foo() { std::cout << "Generic"; }
}
using namespace Inner;
// Specialization of `Outer::foo` is not possible
// it should be `Outer::Inner::foo`.
}
Inline namespace is a way to allow several version to cohabit and defaulting to the inline one
namespace MyNamespace
{
// Inline the last version
inline namespace Version2
{
void foo(); // New version
void bar();
}
https://riptutorial.com/ 409
{
void foo();
}
Unnamed/anonymous namespaces
An unnamed namespace can be used to ensure names have internal linkage (can only be referred
to by the current translation unit). Such a namespace is defined in the same way as any other
namespace, but without the name:
namespace {
int foo = 42;
}
It is recommended to never use unnamed namespaces in header files as this gives a version of
the content for every translation unit it is included in. This is especially important if you define non-
const globals.
// foo.h
namespace {
std::string globalString;
}
// 1.cpp
#include "foo.h" //< Generates unnamed_namespace{1.cpp}::globalString ...
globalString = "Initialize";
// 2.cpp
#include "foo.h" //< Generates unnamed_namespace{2.cpp}::globalString ...
std::cout << globalString; //< Will always print the empty string
C++17
namespace a {
namespace b {
template<class T>
struct qualifies : std::false_type {};
}
}
https://riptutorial.com/ 410
namespace other {
struct bob {};
}
namespace a::b {
template<>
struct qualifies<::other::bob> : std::true_type {};
}
You can enter both the a and b namespaces in one step with namespace a::b starting in C++17.
This is usually used for renaming or shortening long namespace references such referring to
components of a library.
namespace boost
{
namespace multiprecision
{
class Number ...
}
}
namespace boost
{
namespace multiprecision
{
class Number ...
}
}
However, it is easier to get confused over which namespace you are aliasing when you have
something like this:
https://riptutorial.com/ 411
namespace boost
{
namespace multiprecision
{
class Number ...
}
}
namespace numeric
{
namespace multiprecision
{
class Number ...
}
}
// Not recommended as
// its not explicitly clear whether Name1 refers to
// numeric::multiprecision or boost::multiprecision
namespace Name1 = multiprecision;
Namespace alias
A namespace can be given an alias (i.e., another name for the same namespace) using the
namespace identifier = syntax. Members of the aliased namespace can be accessed by qualifying
them with the name of the alias. In the following example, the nested namespace
AReallyLongName::AnotherReallyLongName is inconvenient to type, so the function qux locally declares
an alias N. Members of that namespace can then be accessed simply using N::.
namespace AReallyLongName {
namespace AnotherReallyLongName {
int foo();
int bar();
void baz(int x, int y);
}
}
void qux() {
namespace N = AReallyLongName::AnotherReallyLongName;
N::baz(N::foo(), N::bar());
}
https://riptutorial.com/ 412
Chapter 71: Non-Static Member Functions
Syntax
• // Calling:
○ variable.member_function();
○ variable_pointer->member_function();
• // Definition:
• // Prototype:
○ class class_name {
○ virt-specifier ret_type member_function() cv-qualifiers virt-specifier-seq;
○ // virt-specifier: "virtual", if applicable.
○ // cv-qualifiers: "const" and/or "volatile", if applicable.
○ // virt-specifier-seq: "override" and/or "final", if applicable.
○ }
Remarks
A non-static member function is a class/struct/union member function, which is called on a
particular instance, and operates on said instance. Unlike static member functions, it cannot be
called without specifying an instance.
For information on classes, structures, and unions, please see the parent topic.
Examples
Non-static Member Functions
A class or struct can have member functions as well as member variables. These functions have
syntax mostly similar to standalone functions, and can be defined either inside or outside the class
definition; if defined outside the class definition, the function's name is prefixed with the class'
name and the scope (::) operator.
class CL {
public:
void definedInside() {}
void definedOutside();
};
https://riptutorial.com/ 413
void CL::definedOutside() {}
These functions are called on an instance (or reference to an instance) of the class with the dot (.)
operator, or a pointer to an instance with the arrow (->) operator, and each call is tied to the
instance the function was called on; when a member function is called on an instance, it has
access to all of that instance's fields (through the this pointer), but can only access other
instances' fields if those instances are supplied as parameters.
struct ST {
ST(const std::string& ss = "Wolf", int ii = 359) : s(ss), i(ii) { }
private:
std::string s;
int i;
};
ST st1;
ST st2("Species", 8472);
These functions are allowed to access member variables and/or other member functions,
regardless of either the variable or function's access modifiers. They can also be written out-of-
order, accessing member variables and/or calling member functions declared before them, as the
entire class definition must be parsed before the compiler can begin to compile a class.
class Access {
public:
Access(int i_ = 8088, int j_ = 8086, int k_ = 6502) : i(i_), j(j_), k(k_) {}
int i;
int get_k() const { return k; }
bool private_no_more() const { return i_be_private(); }
protected:
int j;
int get_i() const { return i; }
private:
int k;
int get_j() const { return j; }
bool i_be_private() const { return ((i > j) && (k < j)); }
};
Encapsulation
A common use of member functions is for encapsulation, using an accessor (commonly known as
a getter) and a mutator (commonly known as a setter) instead of accessing fields directly.
class Encapsulator {
int encapsulated;
public:
https://riptutorial.com/ 414
int get_encapsulated() const { return encapsulated; }
void set_encapsulated(int e) { encapsulated = e; }
void some_func() {
do_something_with(encapsulated);
}
};
Inside the class, encapsulated can be freely accessed by any non-static member function; outside
the class, access to it is regulated by member functions, using get_encapsulated() to read it and
set_encapsulated() to modify it. This prevents unintentional modifications to the variable, as
separate functions are used to read and write it. [There are many discussions on whether getters
and setters provide or break encapsulation, with good arguments for both claims; such heated
debate is outside the scope of this example.]
When a base class provides a set of overloaded functions, and a derived class adds another
overload to the set, this hides all of the overloads provided by the base class.
struct HiddenBase {
void f(int) { std::cout << "int" << std::endl; }
void f(bool) { std::cout << "bool" << std::endl; }
void f(std::string) { std::cout << "std::string" << std::endl; }
};
// ...
HiddenBase hb;
HidingDerived hd;
std::string s;
This is due to name resolution rules: During name lookup, once the correct name is found, we stop
looking, even if we clearly haven't found the correct version of the entity with that name (such as
with hd.f(s)); due to this, overloading the function in the derived class prevents name lookup from
discovering the overloads in the base class. To avoid this, a using-declaration can be used to
"import" names from the base class into the derived class, so that they will be available during
name lookup.
https://riptutorial.com/ 415
lookup.
using HiddenBase::f;
// ...
HidingDerived hd;
If a derived class imports names with a using-declaration, but also declares functions with the
same signature as functions in the base class, the base class functions will silently be overridden
or hidden.
struct NamesHidden {
virtual void hide_me() {}
virtual void hide_me(float) {}
void hide_me(int) {}
void hide_me(bool) {}
};
A using-declaration can also be used to change access modifiers, provided the imported entity
was public or protected in the base class.
struct ProMem {
protected:
void func() {}
};
// ...
ProMem pm;
BecomesPub bp;
Similarly, if we explicitly want to call a member function from a specific class in the inheritance
hierarchy, we can qualify the function name when calling the function, specifying that class by
name.
https://riptutorial.com/ 416
struct One {
virtual void f() { std::cout << "One." << std::endl; }
};
// ...
Three t;
Member functions can also be declared virtual. In this case, if called on a pointer or reference to
an instance, they will not be accessed directly; rather, they will look up the function in the virtual
function table (a list of pointers-to-member-functions for virtual functions, more commonly known
as the vtable or vftable), and use that to call the version appropriate for the instance's dynamic
(actual) type. If the function is called directly, from a variable of a class, no lookup is performed.
struct Base {
virtual void func() { std::cout << "In Base." << std::endl; }
};
// ...
Base b;
Derived d;
https://riptutorial.com/ 417
rb.func(); // Output: In Base.
rd.func(); // Output: In Derived.
Note that while pd is Base*, and rd is a Base&, calling func() on either of the two calls Derived::func()
instead of Base::func(); this is because the vtable for Derived updates the Base::func() entry to
instead point to Derived::func(). Conversely, note how passing an instance to slicer() always
results in Base::func() being called, even when the passed instance is a Derived; this is because of
something known as data slicing, where passing a Derived instance into a Base parameter by value
renders the portion of the Derived instance that isn't a Base instance inaccessible.
When a member function is defined as virtual, all derived class member functions with the same
signature override it, regardless of whether the overriding function is specified as virtual or not.
This can make derived classes harder for programmers to parse, however, as there's no indication
as to which function(s) is/are virtual.
struct B {
virtual void f() {}
};
struct D : B {
void f() {} // Implicitly virtual, overrides B::f.
// You'd have to check B to know that, though.
};
Note, however, that a derived function only overrides a base function if their signatures match;
even if a derived function is explicitly declared virtual, it will instead create a new virtual function if
the signatures are mismatched.
struct BadB {
virtual void f() {}
};
C++11
As of C++11, intent to override can be made explicit with the context-sensitive keyword override.
This tells the compiler that the programmer expects it to override a base class function, which
causes the compiler to omit an error if it doesn't override anything.
struct CPP11B {
virtual void f() {}
};
https://riptutorial.com/ 418
This also has the benefit of telling programmers that the function is both virtual, and also declared
in at least one base class, which can make complex classes easier to parse.
When a function is declared virtual, and defined outside the class definition, the virtual specifier
must be included in the function declaration, and not repeated in the definition.
C++11
struct VB {
virtual void f(); // "virtual" goes here.
void g();
};
/* virtual */ void VB::f() {} // Not here.
virtual void VB::g() {} // Error.
If a base class overloads a virtual function, only overloads that are explicitly specified as virtual
will be virtual.
struct BOverload {
virtual void func() {}
void func(int) {}
};
// ...
Const Correctness
One of the primary uses for this cv-qualifiers is const correctness. This is the practice of
guaranteeing that only accesses that need to modify an object are able to modify the object, and
that any (member or non-member) function that doesn't need to modify an object doesn't have
write access to that object (whether directly or indirectly). This prevents unintentional
modifications, making code less errorprone. It also allows any function that doesn't need to modify
state to be able to take either a const or non-const object, without needing to rewrite or overload
the function.
const correctness, due to its nature, starts at the bottom up: Any class member function that
doesn't need to change state is declared as const, so that it can be called on const instances. This,
in turn, allows passed-by-reference parameters to be declared const when they don't need to be
modified, which allows functions to take either const or non-const objects without complaining, and
https://riptutorial.com/ 419
const-ness can propagate outwards in this manner. Due to this, getters are frequently const, as are
any other functions that don't need to modify logical state.
class ConstIncorrect {
Field fld;
public:
ConstIncorrect(const Field& f) : fld(f) {} // Modifies.
class ConstCorrect {
Field fld;
public:
ConstCorrect(const Field& f) : fld(f) {} // Not const: Modifies.
// ...
https://riptutorial.com/ 420
Chapter 72: One Definition Rule (ODR)
Examples
Multiply defined function
The most important consequence of the One Definition Rule is that non-inline functions with
external linkage should only be defined once in a program, although they can be declared multiple
times. Therefore, such functions should not be defined in headers, since a header can be included
multiple times from different translation units.
foo.h:
#ifndef FOO_H
#define FOO_H
#include <iostream>
void foo() { std::cout << "foo"; }
void bar();
#endif
foo.cpp:
#include "foo.h"
void bar() { std:: cout << "bar"; }
main.cpp:
#include "foo.h"
int main() {
foo();
bar();
}
In this program, the function foo is defined in the header foo.h, which is included twice: once from
foo.cpp and once from main.cpp. Each translation unit therefore contains its own definition of foo.
Note that the include guards in foo.h do not prevent this from happening, since foo.cpp and
main.cpp both separately include foo.h. The most likely result of trying to build this program is a
link-time error identifying foo as having been multiply defined.
To avoid such errors, one should declare functions in headers and define them in the
corresponding .cpp files, with some exceptions (see other examples).
Inline functions
A function declared inline may be defined in multiple translation units, provided that all definitions
are identical. It also must be defined in every translation unit in which it is used. Therefore, inline
functions should be defined in headers and there is no need to mention them in the
https://riptutorial.com/ 421
implementation file.
The program will behave as though there is a single definition of the function.
foo.h:
#ifndef FOO_H
#define FOO_H
#include <iostream>
inline void foo() { std::cout << "foo"; }
void bar();
#endif
foo.cpp:
#include "foo.h"
void bar() {
// more complicated definition
}
main.cpp:
#include "foo.h"
int main() {
foo();
bar();
}
In this example, the simpler function foo is defined inline in the header file while the more
complicated function bar is not inline and is defined in the implementation file. Both the foo.cpp and
main.cpp translation units contain definitions of foo, but this program is well-formed since foo is
inline.
A function defined within a class definition (which may be a member function or a friend function)
is implicitly inline. Therefore, if a class is defined in a header, member functions of the class may
be defined within the class definition, even though the definitions may be included in multiple
translation units:
// in foo.h
class Foo {
void bar() { std::cout << "bar"; }
void baz();
};
// in foo.cpp
void Foo::baz() {
// definition
}
The function Foo::baz is defined out-of-line, so it is not an inline function, and must not be defined
in the header.
https://riptutorial.com/ 422
ODR violation via overload resolution
Even with identical tokens for inline functions, ODR can be violated if lookup of names doesn't
refer to the same entity. let's consider func in following:
• header.h
void overloaded(int);
inline void func() { overloaded('*'); }
• foo.cpp
#include "header.h"
void foo()
{
func(); // `overloaded` refers to `void overloaded(int)`
}
• bar.cpp
void bar()
{
func(); // `overloaded` refers to `void overloaded(char)`
}
We have an ODR violation as overloaded refers to different entities depending of the translation
unit.
https://riptutorial.com/ 423
Chapter 73: Operator Overloading
Introduction
In C++, it is possible to define operators such as + and -> for user-defined types. For example, the
<string> header defines a + operator to concatenate strings. This is done by defining an operator
function using the operator keyword.
Remarks
The operators for built-in types cannot be changed, operators can only be overloaded for user-
defined types. That is, at least one of the operands has to be of a user-defined type.
There are some operators that you should not (99.98% of the time) overload:
Why? Because they overload operators that another programmer might never expect, resulting in
different behavior than anticipated.
For example, the user defined && and || overloads of these operators lose their short-circuit
evaluation and lose their special sequencing properties (C++17), the sequencing issue also
applies to , operator overloads.
Examples
Arithmetic operators
• + and +=
• - and -=
• * and *=
• / and /=
https://riptutorial.com/ 424
• & and &=
• | and |=
• ^ and ^=
• >> and >>=
• << and <<=
Overloading for all operators is the same. Scroll down for explanation
Note: operator+ should return by non-const value, as returning a reference wouldn't make sense (it
returns a new object) nor would returning a const value (you should generally not return by const).
The first argument is passed by value, why? Because
1. You can't modify the original object (Object foobar = foo + bar; shouldn't modify foo after all,
it wouldn't make sense)
2. You can't make it const, because you will have to be able to modify the object (because
operator+ is implemented in terms of operator+=, which modifies the object)
Passing by const& would be an option, but then you will have to make a temporary copy of the
passed object. By passing by value, the compiler does it for you.
operator+= returns a reference to the itself, because it is then possible to chain them (don't use the
https://riptutorial.com/ 425
same variable though, that would be undefined behavior due to sequence points).
The first argument is a reference (we want to modify it), but not const, because then you wouldn't
be able to modify it. The second argument should not be modified, and so for performance reason
is passed by const& (passing by const reference is faster than by value).
Unary operators
Overloading is the same for both types (++ and --). Scroll down for explanation
//Postfix operator foo++ (int argument is used to separate pre- and postfix)
//Should be implemented in terms of ++foo (prefix operator)
T operator++(T& lhs, int)
{
T t(lhs);
++lhs;
return t;
}
//Postfix operator foo++ (int argument is used to separate pre- and postfix)
//Should be implemented in terms of ++foo (prefix operator)
T operator++(int)
{
T t(*this);
++(*this);
return t;
}
Note: The prefix operator returns a reference to itself, so that you can continue operations on it.
The first argument is a reference, as the prefix operator changes the object, that's also the reason
why it isn't const (you wouldn't be able to modify it otherwise).
https://riptutorial.com/ 426
The postfix operator returns by value a temporary (the previous value), and so it cannot be a
reference, as it would be a reference to a temporary, which would be garbage value at the end of
the function, because the temporary variable goes out of scope). It also cannot be const, because
you should be able to modify it directly.
The first argument is a non-const reference to the "calling" object, because if it were const, you
wouldn't be able to modify it, and if it weren't a reference, you wouldn't change the original value.
It is because of the copying needed in postfix operator overloads that it's better to make it a habit
to use prefix ++ instead of postfix ++ in for loops. From the for loop perspective, they're usually
functionally equivalent, but there might be a slight performance advantage to using prefix ++,
especially with "fat" classes with a lot of members to copy. Example of using prefix ++ in a for
loop:
Comparison operators
• == and !=
• > and <
• >= and <=
The recommended way to overload all those operators is by implementing only 2 operators (==
and <) and then using those to define the rest. Scroll down for explanation
//Note that the functions are const, because if they are not const, you wouldn't be able
//to call them if the object is const
https://riptutorial.com/ 427
//Now you can define the rest
bool operator!=(const T& rhs) const { return !(*this == rhs); }
bool operator>(const T& rhs) const { return rhs < *this; }
bool operator<=(const T& rhs) const { return !(*this > rhs); }
bool operator>=(const T& rhs) const { return !(*this < rhs); }
The operators obviously return a bool, indicating true or false for the corresponding operation.
All of the operators take their arguments by const&, because the only thing that does operators do
is compare, so they shouldn't modify the objects. Passing by & (reference) is faster than by value,
and to make sure that the operators don't modify it, it is a const-reference.
Note that the operators inside the class/struct are defined as const, the reason for this is that
without the functions being const, comparing const objects would not be possible, as the compiler
doesn't know that the operators don't modify anything.
Conversion operators
You can overload type operators, so that your type can be implicitly converted into the specified
type.
Example:
struct Text
{
std::string text;
Text t;
t.text = "Hello world!";
//Ok
const char* copyoftext = t;
You should always (99.98% of the time) implement 2 versions, a const and a not-const version,
because if the object is const, it should not be able to modify the object returned by [].
https://riptutorial.com/ 428
The arguments are passed by const& instead of by value because passing by reference is faster
than by value, and const so that the operator doesn't change the index accidentally.
The operators return by reference, because by design you can modify the object [] return, i.e:
std::vector<int> v{ 1 };
v[0] = 2; //Changes value of 1 to 2
//wouldn't be possible if not returned by reference
Multiple subscript operators, [][]..., can be achieved via proxy objects. The following example of
a simple row-major matrix class demonstrates this:
template<class T>
class matrix {
// class enabling [][] overload to access matrix elements
template <class C>
class proxy_row_vector {
using reference = decltype(std::declval<C>()[0]);
using const_reference = decltype(std::declval<C const>()[0]);
public:
proxy_row_vector(C& _vec, std::size_t _r_ind, std::size_t _cols)
: vec(_vec), row_index(_r_ind), cols(_cols) {}
const_reference operator[](std::size_t _col_index) const {
return vec[row_index*cols + _col_index];
}
reference operator[](std::size_t _col_index) {
return vec[row_index*cols + _col_index];
}
private:
C& vec;
std::size_t row_index; // row index to access
std::size_t cols; // number of columns in matrix
};
https://riptutorial.com/ 429
: mtx(_rows*_cols), rows(_rows), cols(_cols) {}
For example:
struct Sum
{
int operator()(int a, int b)
{
return a + b;
}
};
Assignment operator
The assignment operator is one of the most important operators because it allows you to change
the status of a variable.
If you do not overload the assigment operator for your class/struct, it is automatically generated by
the compiler: the automatically-generated assignment operator performs a "memberwise
assignment", ie by invoking assignment operators on all members, so that one object is copied to
https://riptutorial.com/ 430
the other, a member at time. The assignment operator should be overloaded when the simple
memberwise assignment is not suitable for your class/struct, for example if you need to perform a
deep copy of an object.
Overloading the assignment operator = is easy, but you should follow some simple steps.
Note: other is passed by const&, because the object being assigned should not be changed, and
passing by reference is faster than by value, and to make sure than operator= doesn't modify it
accidentally, it is const.
The assignment operator can only to be overloaded in the class/struct, because the left value of =
is always the class/struct itself. Defining it as a free function doesn't have this guarantee, and is
disallowed because of that.
When you declare it in the class/struct, the left value is implicitly the class/struct itself, so there is
no problem with that.
Overloading the bitwise NOT (~) is fairly simple. Scroll down for explanation
T operator~(T lhs)
{
//Do operation
return lhs;
}
https://riptutorial.com/ 431
T operator~()
{
T t(*this);
//Do operation
return t;
}
Note: operator~ returns by value, because it has to return a new value (the modified value), and
not a reference to the value (it would be a reference to the temporary object, which would have
garbage value in it as soon as the operator is done). Not const either because the calling code
should be able to modify it afterwards (i.e. int a = ~a + 1; should be possible).
Inside the class/struct you have to make a temporary object, because you can't modify this, as it
would modify the original object, which shouldn't be the case.
The operators << and >> are commonly used as "write" and "read" operators:
• std::ostream overloads << to write variables to the underlying stream (example: std::cout)
• std::istream overloads >> to read from the underlying stream to a variable (example: std::cin
)
The way they do this is similar if you wanted to overload them "normally" outside of the class/
struct, except that specifying the arguments are not of the same type:
• Return type is the stream you want to overload from (for example, std::ostream) passed by
reference, to allow chaining (Chaining: std::cout << a << b;). Example: std::ostream&
• lhs would be the same as the return type
• rhs is the type you want to allow overloading from (i.e. T), passed by const& instead of value
for performance reason (rhs shouldn't be changed anyway). Example: const Vector&.
Example:
Vector v = { 1, 2, 3};
The code below implements a very simple complex number type for which the underlying field is
automatically promoted, following the language's type promotion rules, under application of the
https://riptutorial.com/ 432
four basic operators (+, -, *, and /) with a member of a different field (be it another complex<T> or
some scalar type).
This is intended to be a holistic example covering operator overloading alongside basic use of
templates.
#include <type_traits>
namespace not_std{
using std::decay_t;
//----------------------------------------------------------------
// complex< value_t >
//----------------------------------------------------------------
template<typename value_t>
struct complex
{
value_t x;
value_t y;
https://riptutorial.com/ 433
this->x /= s;
this->y /= s;
return *this;
}
complex &operator /= (const complex &other)
{
(*this) = (*this) / other;
return *this;
}
template<typename other_value_t>
explicit complex(const complex<other_value_t> &other)
: x{static_cast<const value_t &>(other.x)}
, y{static_cast<const value_t &>(other.y)}
{}
//----------------------------------------------------------------
// operator - (negation)
//----------------------------------------------------------------
template<typename value_t>
complex<value_t> operator - (const complex<value_t> &z)
{ return {-z.x, -z.y}; }
//----------------------------------------------------------------
// operator +
//----------------------------------------------------------------
//----------------------------------------------------------------
https://riptutorial.com/ 434
// operator -
//----------------------------------------------------------------
//----------------------------------------------------------------
// operator *
//----------------------------------------------------------------
//----------------------------------------------------------------
// operator /
//----------------------------------------------------------------
https://riptutorial.com/ 435
const auto s = a/absqr(b);
return {
b.x * s,
-b.y * s
};
}
// makes a complex<double>
auto dz = fz * 1.0;
// still a complex<double>
auto idz = 1.0f/dz;
// also a complex<double>
auto one = dz * idz;
// a complex<double> again
auto one_again = fz * idz;
https://riptutorial.com/ 436
auto e6 = b / 1;
auto e7 = 1 / b;
return 0;
}
Named operators
You can extend C++ with named operators that are "quoted" by standard C++ operators.
namespace named_operator {
template<class D>struct make_operator{constexpr make_operator(){}};
namespace my_ns {
struct append_t : named_operator::make_operator<append_t> {};
constexpr append_t append{};
std::vector<int> a {1,2,3};
std::vector<int> b {4,5,6};
auto c = a *append* b;
We then overload named_invoke( lhs, append_t, rhs ) for the types we want on the right and left.
https://riptutorial.com/ 437
The library overloads lhs*append_t, returning a temporary half_apply object. It also overloads
half_apply*rhs to call named_invoke( lhs, append_t, rhs ).
We simply have to create the proper append_t token and do an ADL-friendly named_invoke of the
proper signature, and everything hooks up and works.
For a more complex example, suppose you want to have element-wise multiplication of elements
of a std::array:
template<class=void, std::size_t...Is>
auto indexer( std::index_sequence<Is...> ) {
return [](auto&& f) {
return f( std::integral_constant<std::size_t, Is>{}... );
};
}
template<std::size_t N>
auto indexer() { return indexer( std::make_index_sequence<N>{} ); }
namespace my_ns {
struct e_times_t : named_operator::make_operator<e_times_t> {};
constexpr e_times_t e_times{};
live example.
This element-wise array code can be extended to work on tuples or pairs or C-style arrays, or
even variable length containers if you decide what to do if the lengths don't match.
You could also an element-wise operator type and get lhs *element_wise<'+'>* rhs.
Writing a *dot* and *cross* product operators are also obvious uses.
The use of * can be extended to support other delimiters, like +. The delimeter precidence
determines the precidence of the named operator, which may be important when translating
physics equations over to C++ with minimal use of extra ()s.
With a slight change in the library above, we can support ->*then* operators and extend
std::function prior to the standard being updated, or write monadic ->*bind*. It could also have a
stateful named operator, where we carefully pass the Op down to the final invoke function,
permitting:
https://riptutorial.com/ 438
named_operator<'*'> append = [](auto lhs, auto&& rhs) {
using std::begin; using std::end;
lhs.insert( end(lhs), begin(rhs), end(rhs) );
return std::move(lhs);
};
https://riptutorial.com/ 439
Chapter 74: operator precedence
Remarks
Operators are listed top to bottom, in descending precedence. Operators with the same number
have equal precedence and the same associativity.
1. ::
2. The postfix operators: [] () T(...) . -> ++ -- dynamic_cast static_cast reinterpret_cast
const_cast typeid
3. The unary prefix operators: ++ -- * & + - ! ~ sizeof new delete delete[]; the C-style cast
notation, (T)...; (C++11 and above) sizeof... alignof noexcept
4. .* and ->*
5. *, /, and %, binary arithmetic operators
6. + and -, binary arithmetic operators
7. << and >>
8. <, >, <=, >=
9. == and !=
10. &, the bitwise AND operator
11. ^
12. |
13. &&
14. ||
15. ?: (ternary conditional operator)
16. =, *=, /=, %=, +=, -=, >>=, <<=, &=, ^=, |=
17. throw
18. , (the comma operator)
The assignment, compound assignment, and ternary conditional operators are right-associative.
All other binary operators are left-associative.
The rules for the ternary conditional operator are a bit more complicated than simple precedence
rules can express.
• An operand binds less tightly to a ? on its left or a : on its right than to any other operator.
Effectively, the second operand of the conditional operator is parsed as though it is
parenthesized. This allows an expression such as a ? b , c : d to be syntactically valid.
• An operand binds more tightly to a ? on its right than to an assignment operator or throw on
its left, so a = b ? c : d is equivalent to a = (b ? c : d) and throw a ? b : c is equivalent to
throw (a ? b : c).
• An operand binds more tightly to an assignment operator on its right than to : on its left, so a
? b : c = d is equivalent to a ? b : (c = d).
Examples
Arithmetic operators
https://riptutorial.com/ 440
Arithmetic operators in C++ have the same precedence as they do in mathematics:
Multiplication and division have left associativity(meaning that they will be evaluated from left to
right) and they have higher precedence than addition and subtraction, which also have left
associativity.
We can also force the precedence of expression using parentheses ( ). Just the same way as you
would do that in normal mathematics.
//Addition:
//With Multiplication
These operators have the usual precedence in C++: AND before OR.
Adding the parenthesis does not change the behavior, though, it does make it easier to read. By
adding these parentheses, no confusion exist about the intent of the writer.
&& has precedence over ||, this means that parentheses are placed to evaluate what would be
evaluated together.
https://riptutorial.com/ 441
#include <iostream>
#include <string>
int main(){
bool result;
//let's evaluate 3 booleans with || and && to illustrate operator precedence
//precedence does not mean that && will be evaluated first but rather where
//parentheses would be added
//example 1
result =
False("A") || False("B") && False("C");
// eq. False("A") || (False("B") && False("C"))
//FalseA
//FalseB
//"Short-circuit evaluation skip of C"
//A is false so we have to evaluate the right of ||,
//B being false we do not have to evaluate C to know that the result is false
result =
True("A") || False("B") && False("C");
// eq. True("A") || (False("B") && False("C"))
cout << result << " :=====================" << endl;
//TrueA
//"Short-circuit evaluation skip of B"
//"Short-circuit evaluation skip of C"
//A is true so we do not have to evaluate
// the right of || to know that the result is true
//If || had precedence over && the equivalent evaluation would be:
// (True("A") || False("B")) && False("C")
//What would print
//TrueA
//"Short-circuit evaluation skip of B"
//FalseC
//Because the parentheses are placed differently
//the parts that get evaluated are differently
//which makes that the end result in this case would be False because C is false
}
Unary Operators
Unary operators act on the object upon which they are called and have high precedence. (See
Remarks)
When used postfix, the action occurs only after the entire operation is evaluated, leading to some
https://riptutorial.com/ 442
interesting arithmetics:
int a = 1;
++a; // result: 2
a--; // result: 1
int minusa=-a; // result: -1
bool b = true;
!b; // result: true
a=4;
int c = a++/2; // equal to: (a==4) 4 / 2 result: 2 ('a' incremented postfix)
cout << a << endl; // prints 5!
int d = ++a/2; // equal to: (a+1) == 6 / 2 result: 3
https://riptutorial.com/ 443
Chapter 75: Optimization
Introduction
When compiling, the compiler will often modify the program to increase performance. This is
permitted by the as-if rule, which allows any and all transformations that do not change observable
behavior.
Examples
Inline Expansion/Inlining
Inline expansion (also known as inlining) is compiler optimisation that replaces a call to a function
with the body of that function. This saves the function call overhead, but at the cost of space, since
the function may be duplicated several times.
// source:
int foo(int a)
{
return process(a);
}
int foo(int a)
{
return 2 * a; // the body of process() is copied into foo()
}
Inlining is most commonly done for small functions, where the function call overhead is significant
compared to the size of the function body.
The size of any object or member subobject is required to be at least 1 even if the type is an
empty class type (that is, a class or struct that has no non-static data members), in order to be
able to guarantee that the addresses of distinct objects of the same type are always distinct.
However, base class subobjects are not so constrained, and can be completely optimized out from
the object layout:
#include <cassert>
https://riptutorial.com/ 444
struct Base {}; // empty class
int main() {
// the size of any object of empty class type is at least 1
assert(sizeof(Base) == 1);
Reference: cppreference
https://riptutorial.com/ 445
Chapter 76: Optimization in C++
Examples
Empty Base Class Optimization
An object cannot occupy less than 1 byte, as then the members of an array of this type would
have the same address. Thus sizeof(T)>=1 always holds. It's also true that a derived class cannot
be smaller than any of its base classes. However, when the base class is empty, its size is not
necessarily added to the derived class:
In this case, it's not required to allocate a byte for Base within Derived to have a distinct address per
type per object. If empty base class optimization is performed (and no padding is required), then
sizeof(Derived) == sizeof(int), that is, no additional allocation is done for the empty base. This is
possible with multiple base classes as well (in C++, multiple bases cannot have the same type, so
no issues arise from that).
Note that this can only be performed if the first member of Derived differs in type from any of the
base classes. This includes any direct or indirect common bases. If it's the same type as one of
the bases (or there's a common base), at least allocating a single byte is required to ensure that
no two distinct objects of the same type have the same address.
Introduction to performance
C and C++ are well known as high-performance languages - largely due to the heavy amount of
code customization, allowing a user to specify performance by choice of structure.
When optimizing it is important to benchmark relevant code and completely understand how the
code will be used.
• Premature optimization: Complex code may perform worse after optimization, wasting time
and effort. First priority should be to write correct and maintainable code, rather than
optimized code.
• Optimization for the wrong use case: Adding overhead for the 1% might not be worth the
slowdown for the other 99%
• Micro-optimization: Compilers do this very efficiently and micro-optimization can even hurt
the compilers ability to further optimize the code
https://riptutorial.com/ 446
Typical optimization goals are:
• To do less work
• To use more efficient algorithms/structures
• To make better use of hardware
The most straightforward approach to optimizing is by executing less code. This approach usually
gives a fixed speed-up without changing the time complexity of the code.
Even though this approach gives you a clear speedup, this will only give noticable improvements
when the code is called a lot.
C++14
From C++14, compilers are allowed to optimize this code to remove the allocation and matching
deallocation.
// Within this function, we will have the same noticeable effect as the slow variant while
going at double speed as we only traverse once through the code
https://riptutorial.com/ 447
const A *lazyLookupSlow(const std::string &key) {
auto &value = lookup[key];
if (!value)
value = std::make_unique<A>();
return value.get();
}
A similar approach to this optimization can be used to implement a stable version of unique
Optimizing by using the right data structures at the right time can change the time-complexity of
the code.
https://riptutorial.com/ 448
// This variant of stableUnique contains a complexity of N log(N)
// N > number of elements in v
// log(N) > insert complexity of std::set
std::vector<std::string> stableUnique(const std::vector<std::string> &v) {
std::vector<std::string> result;
std::set<std::string> checkUnique;
for (const auto &s : v) {
// See Optimizing by executing less code
if (checkUnique.insert(s).second)
result.push_back(s);
}
return result;
}
By using a container which uses a different implementation for storing its elements (hash container
instead of tree), we can transform our implementation to complexity N. As a side effect, we will call
the comparison operator for std::string less, as it only has to be called when the inserted string
should end up in the same bucket.
Small object optimization is a technique which is used within low level data structures, for instance
the std::string (Sometimes referred to as Short/Small String Optimization). It's meant to use stack
space as a buffer instead of some allocated memory in case the content is small enough to fit
within the reserved space.
By adding extra memory overhead and extra calculations, it tries to prevent an expensive heap
allocation. The benefits of this technique are dependent on the usage and can even hurt
performance if incorrectly used.
Example
A very naive way of implementing a string with this optimization would the following:
#include <cstring>
https://riptutorial.com/ 449
constexpr static auto SMALL_BUFFER_SIZE = 16;
public:
~string()
{
if (_isAllocated)
delete [] _buffer;
}
string(string &&rhs)
: _isAllocated(rhs._isAllocated)
, _buffer(rhs._buffer)
, _smallBuffer(rhs._smallBuffer) //< Not needed if allocated
{
if (_isAllocated)
{
// Prevent double deletion of the memory
rhs._buffer = nullptr;
}
else
{
// Copy over data
std::strcpy(_smallBuffer, rhs._smallBuffer);
_buffer = &_smallBuffer[0];
}
}
// Other methods, including other constructors, copy constructor,
// assignment operators have been omitted for readability
};
As you can see in the code above, some extra complexity has been added in order to prevent
some new and delete operations. On top of this, the class has a larger memory footprint which
might not be used except in a couple of cases.
Often it is tried to encode the bool value _isAllocated, within the pointer _buffer with bit
manipulation to reduce the size of a single instance (intel 64 bit: Could reduce size by 8 byte). An
optimization which is only possible when its known what the alignment rules of the platform is.
When to use?
https://riptutorial.com/ 450
As this optimization adds a lot of complexity, it is not recommended to use this optimization on
every single class. It will often be encountered in commonly used, low-level data structures. In
common C++11 standard library implementations one can find usages in std::basic_string<> and
std::function<>.
As this optimization only prevents memory allocations when the stored data is smaller than the
buffer, it will only give benefits if the class is often used with small data.
A final drawback of this optimization is that extra effort is required when moving the buffer, making
the move-operation more expensive than when the buffer would not be used. This is especially
true when the buffer contains a non-POD type.
https://riptutorial.com/ 451
Chapter 77: Overload resolution
Remarks
Overload resolution happens in several different situations
• Calls to named overloaded functions. The candidates are all the functions found by name
lookup.
• Calls to class object. The candidates are usually all the overloaded function call operators of
the class.
• Use of an operator. The candidates are the overloaded operator functions at namespace
scope, the overloaded operator functions in the left class object (if any) and the built-in
operators.
• Overload resolution to find the correct conversion operator function or constructor to invoke
for an initialization
○For non-list direct initialization (Class c(value)), the candidates are constructors of Class
.
○For non-list copy initialization (Class c = value) and for finding the user defined
conversion function to invoke in a user defined conversion sequence. The candidates
are the constructors of Class and if the source is a class object, its conversion operator
functions.
○For initialization of a non-class from a class object (Nonclass c = classObject). The
candidates are the conversion operator functions of the initializer object.
○For initializing a reference with a class object (R &r = classObject), when the class has
conversion operator functions that yield values that can be bound directly to r. The
candidates are such conversion operator functions.
○For list-initialization of a non-aggregate class object (Class c{1, 2, 3}), the candidates
are the initializer list constructors for a first pass through overload resolution. If this
doesn't find a viable candidate, a second pass through overload resolution is done,
with the constructors of Class as candidates.
Examples
Exact match
An overload without conversions needed for parameter types or only conversions needed between
types that are still considered exact matches is preferred over an overload that requires other
conversions in order to call.
When an argument binds to a reference to the same type, the match is considered to not require a
conversion even if the reference is more cv-qualified.
https://riptutorial.com/ 452
void f(int& x);
void f(double x);
int x = 42;
f(x); // argument type is int; exact match with int&
For the purposes of overload resolution, the type "array of T" is considered to match exactly with
the type "pointer to T", and the function type T is considered to match exactly with the function
pointer type T*, even though both require conversions.
int a[100];
f(a); // calls f(int*); exact match with array-to-pointer conversion
g(a); // ambiguous; both overloads give exact match
Overload resolution partitions the cost of passing an argument to a parameter into one of four
different categorizes, called "sequences". Each sequence may include zero, one or several
conversions
The general principle is that Standard conversion sequences are the cheapest, followed by user
defined conversion sequences, followed by ellipsis conversion sequences.
A special case is the list initialization sequence, which does not constitute a conversion (an
initializer list is not an expression with a type). Its cost is determined by defining it to be equivalent
https://riptutorial.com/ 453
to one of the other three conversion sequences, depending on the parameter type and form of
initializer list.
Overload resolution occurs after name lookup. This means that a better-matching function will not
be selected by overload resolution if it loses name lookup:
Overload resolution occurs before access checking. An inaccessible function might be selected by
overload resolution if it is a better match than an accessible function.
class C {
public:
static void f(double x);
private:
static void f(int x);
};
C::f(42); // Error! Calls private C::f(int) even though public C::f(double) is viable.
Similarly, overload resolution happens without checking whether the resulting call is well-formed
with regards to explicit:
struct X {
explicit X(int );
X(char );
};
void foo(X );
foo({4}); // X(int) is better much, but expression is
// ill-formed because selected constructor is explicit
You must be very careful when providing a forwarding reference overload as it may match too
well:
struct A {
A() = default; // #1
A(A const& ) = default; // #2
The intent here was that A is copyable, and that we have this other constructor that might initialize
https://riptutorial.com/ 454
some other member. However:
A a; // calls #1
A b(a); // calls #3!
A(A const& ); // #2
A(A& ); // #3, with T = A&
Both are Exact Matches, but #3 takes a reference to a less cv-qualified object than #2 does, so it
has the better standard conversion sequence and is the best viable function.
The solution here is to always constrain these constructors (e.g. using SFINAE):
template <class T,
class = std::enable_if_t<!std::is_convertible<std::decay_t<T>*, A*>::value>
>
A(T&& );
The type trait here is to exclude any A or class publicly and unambiguously derived from A from
consideration, which would make this constructor ill-formed in the example described earlier (and
hence removed from the overload set). As a result, the copy constructor is invoked - which is what
we wanted.
1. Find candidate functions via name lookup. Unqualified calls will perform both regular
unqualified lookup as well as argument-dependent lookup (if applicable).
2. Filter the set of candidate functions to a set of viable functions. A viable function for which
there exists an implicit conversion sequence between the arguments the function is called
with and the parameters the function takes.
3. Pick the best viable candidate. A viable function F1 is a better function than another viable
function F2 if the implicit conversion sequence for each argument in F1 is not worse than the
corresponding implicit conversion sequence in F2, and...:
3.1. For some argument, the implicit conversion sequence for that argument in F1 is a better
https://riptutorial.com/ 455
conversion sequence than for that argument in F2, or
3.2. In a user-defined conversion, the standard conversion sequence from the return of F1 to
the destination type is a better conversion sequence than that of the return type of F2, or
struct A
{
operator int();
operator double();
} a;
3.3. In a direct reference binding, F1 has the same kind of reference by F2 is not, or
struct A
{
operator X&(); // #1
operator X&&(); // #2
};
A a;
X& lx = a; // calls #1
X&& rx = a; // calls #2
3.5. F1 and F2 are both function template specializations, but F1 is more specialized than F2.
int* p;
f(p); // calls #2, more specialized
The ordering here is significant. The better conversion sequence check happens before the
template vs non-template check. This leads to a common error with overloading on forwarding
reference:
struct A {
A(A const& ); // #1
https://riptutorial.com/ 456
template <class T>
A(T&& ); // #2, not constrained
};
A a;
A b(a); // calls #2!
// #1 is not a template but #2 resolves to
// A(A& ), which is a less cv-qualified reference than #1
// which makes it a better implicit conversion sequence
If there's no single best viable candidate at the end, the call is ambiguous:
void f(double ) { }
void f(float ) { }
Converting an integer type to the corresponding promoted type is better than converting it to some
other integer type.
Promoting a float to double is better than converting it to some other floating point type.
Arithmetic conversions other than promotions are neither better nor worse than each other.
Therefore, in order to ensure that there will be no ambiguity when calling a function f with either
integral or floating-point arguments of any standard type, a total of eight overloads are needed, so
that for each possible argument type, either an overload matches exactly or the unique overload
with the promoted argument type will be selected.
https://riptutorial.com/ 457
void f(unsigned int x);
void f(long x);
void f(unsigned long x);
void f(long long x);
void f(unsigned long long x);
void f(double x);
void f(long double x);
struct A { int m; };
struct B : A {};
struct C : B {};
The conversion from derived class type to base class type is preferred to user-defined
conversions. This applies when passing by value or by reference, as well as when converting
pointer-to-derived to pointer-to-base.
struct Unrelated {
Unrelated(B b);
};
void f(A a);
void f(Unrelated u);
B b;
f(b); // calls f(A)
A pointer conversion from derived class to base class is also better than conversion to void*.
If there are multiple overloads within the same chain of inheritance, the most derived base class
overload is preferred. This is based on a similar principle as virtual dispatch: the "most
specialized" implementation is chosen. However, overload resolution always occurs at compile
time and will never implicitly down-cast.
For pointers to members, which are contravariant with respect to the class, a similar rule applies in
the opposite direction: the least derived derived class is preferred.
https://riptutorial.com/ 458
void f(int C::*p);
int A::*p = &A::m;
f(p); // calls f(int B::*)
Base b;
f(&b); // f(Base*) is better than f(const Base*)
Derived d;
f(&d); // f(const Derived*) is better than f(Base*) though;
// constness is only a "tie-breaker" rule
Likewise, passing an argument to a T& parameter, if possible, is better than passing it to a const T&
parameter, even if both have exact match rank.
This rule applies to const-qualified member functions as well, where it is important for allowing
mutable access to non-const objects and immutable access to const objects.
class IntVector {
public:
// ...
int* data() { return m_data; }
const int* data() const { return m_data; }
private:
// ...
int* m_data;
};
IntVector v1;
int* data1 = v1.data(); // Vector::data() is better than Vector::data() const;
// data1 can be used to modify the vector's data
const IntVector v2;
const int* data2 = v2.data(); // only Vector::data() const is viable;
// data2 can't be used to modify the vector's data
In the same way, a volatile overload will be less preferred than a non-volatile overload.
class AtomicInt {
https://riptutorial.com/ 459
public:
// ...
int load();
int load() volatile;
private:
// ...
};
AtomicInt a1;
a1.load(); // non-volatile overload preferred; no side effect
volatile AtomicInt a2;
a2.load(); // only volatile overload is viable; side effect
static_cast<volatile AtomicInt&>(a1).load(); // force volatile semantics for a1
https://riptutorial.com/ 460
Chapter 78: Parameter packs
Examples
A template with a parameter pack
1
2
3
hello
https://riptutorial.com/ 461
Chapter 79: Perfect Forwarding
Remarks
Perfect forwarding requires forwarding references in order to preserve the ref-qualifiers of the
arguments. Such references appear only in a deduced context. That is:
template<class T>
void f(T&& x) // x is a forwarding reference, because T is deduced from a call to f()
{
g(std::forward<T>(x)); // g() will receive an lvalue or an rvalue, depending on x
}
The following does not involve perfect forwarding, because T is not deduced from the constructor
call:
template<class T>
struct a
{
a(T&& x); // x is a rvalue reference, not a forwarding reference
};
C++17
C++17 will allow deduction of class template arguments. The constructor of "a" in the above
example will become a user of a forwarding reference
a example1(1);
// same as a<int> example1(1);
int x = 1;
a example2(x);
// same as a<int&> example2(x);
Examples
Factory functions
Suppose we want to write a factory function that accepts an arbitrary list of arguments and passes
those arguments unmodified to another function. An example of such a function is make_unique,
which is used to safely construct a new instance of T and return a unique_ptr<T> that owns the
instance.
The language rules regarding variadic templates and rvalue references allows us to write such a
function.
https://riptutorial.com/ 462
{
return unique_ptr<T>(new T(std::forward<A>(args)...));
}
The use of ellipses ... indicate a parameter pack, which represents an arbitrary number of types.
The compiler will expand this parameter pack to the correct number of arguments at the call site.
These arguments are then passed to T's constructor using std::forward. This function is required
to preserve the ref-qualifiers of the arguments.
struct foo
{
foo() {}
foo(const foo&) {} // copy constructor
foo(foo&&) {} // copy constructor
foo(int, int, int) {}
};
foo f;
auto p1 = make_unique<foo>(f); // calls foo::foo(const foo&)
auto p2 = make_unique<foo>(std::move(f)); // calls foo::foo(foo&&)
auto p3 = make_unique<foo>(1, 2, 3);
https://riptutorial.com/ 463
Chapter 80: Pimpl Idiom
Remarks
The pimpl idiom (pointer to implementation, sometimes referred to as opaque pointer or cheshire
cat technique), reduces the compilation times of a class by moving all its private data members
into a struct defined in the .cpp file.
The class owns a pointer to the implementation. This way, it can be forward declared, so that the
header file does not need to #include classes that are used in private member variables.
When using the pimpl idiom, changing a private data member does not require recompiling
classes that depend on it.
Examples
Basic Pimpl idiom
C++11
// widget.h
class Widget
{
public:
Widget();
~Widget();
void DoSomething();
private:
// the pImpl idiom is named after the typical variable name used
// ie, pImpl:
struct Impl; // forward declaration
std::experimental::propagate_const<std::unique_ptr< Impl >> pImpl; // ptr to actual
implementation
};
// widget.cpp
#include "widget.h"
#include "reallycomplextype.h" // no need to include this header inside widget.h
struct Widget::Impl
{
https://riptutorial.com/ 464
// the attributes needed from Widget go here
ReallyComplexType rct;
};
Widget::Widget() :
pImpl(std::make_unique<Impl>())
{}
Widget::~Widget() = default;
void Widget::DoSomething()
{
// do the stuff here with pImpl
}
The pImpl contains the Widget state (or some/most of it). Instead of the Widget description of state
being exposed in the header file, it can be only exposed within the implementation.
pImpl stands for "pointer to implementation". The "real" implementation of Widget is in the pImpl.
Danger: Note that for this to work with unique_ptr, ~Widget() must be implemented at a point in a
file where the Impl is fully visible. You can =default it there, but if =default where Impl is undefined,
the program may easily become ill-formed, no diagnostic required.
https://riptutorial.com/ 465
Chapter 81: Pointers
Introduction
A pointer is an address that refers to a location in memory. They're commonly used to allow
functions or data structures to know of and modify memory without having to copy the memory
referred to. Pointers are usable with both primitive (built-in) or user-defined types.
Pointers make use of the "dereference" * , "address of" & , and "arrow" -> operators. The '*' and '->'
operators are used to access the memory being pointed at, and the & operator is used to get an
address in memory.
Syntax
• <Data type> *<Variable name>;
• <Data type> *<Variable name> = &<Variable name of same Data type>;
• <Data type> *<Variable name> = <Value of same Data type>;
• int *foo; //A pointer which would points to an integer value
• int *bar = &myIntVar;
• long *bar[2];
• long *bar[] = {&myLongVar1, &myLongVar2}; //Equals to: long *bar[2]
Remarks
Be aware of problems when declaring multiple pointers on the same line.
Examples
Pointer basics
C++11
Note: in all the following, the existence of the C++11 constant nullptr is assumed. For earlier
versions, replace nullptr with NULL, the constant that used to play a similar role.
https://riptutorial.com/ 466
A pointer variable can be created using the specific * syntax, e.g. int *pointer_to_int;.
When a variable is of a pointer type (int *), it just contains a memory address. The memory
address is the location at which data of the underlying type (int) is stored.
The difference is clear when comparing the size of a variable with the size of a pointer to the same
type:
/* Produces:
sizeof(bar) = 24
sizeof(p_bar0) = 8
*/
You can get the memory address of a variable of a given type by prefixing the variable with the
address of operator &. The value returned by & is a pointer to the underlying type which contains
the memory address of the variable (which is valid data as long as the variable does not go out
of scope).
p_bar0 = p_bar2;
https://riptutorial.com/ 467
// p_bar0 is now &bar.
p_bar2 = nullptr;
// p_bar0 == &bar
// p_bar1 == nullptr
// p_bar2 == nullptr
• assigning two pointers does not overwrite the memory that the assigned pointer refers to;
• pointers can be null.
• the address of operator is required explicitly.
(*p_bar0).foo1 = 5;
// Prints 5 as well
std::cout << "baz.foo1 = " << baz.foo1 << std::endl;
big_struct *never_do_this() {
// This is a local variable. Outside `never_do_this` it doesn't exist.
big_struct retval;
retval.foo1 = 11;
https://riptutorial.com/ 468
// This returns the address of `retval`.
return &retval;
// `retval` is destroyed and any code using the value returned
// by `never_do_this` has a pointer to a memory location that
// contains garbage data (or is inaccessible).
}
(Clang) warning: address of stack memory associated with local variable 'retval' returned [-
Wreturn-stack-address]
(Gcc) warning: address of local variable ‘retval’ returned [-Wreturn-local-addr]
Hence, care must be taken when pointers are arguments of functions, as they could be null:
// Segmentation fault.
naive_code(nullptr);
Pointer Operations
There are two operators for pointers: Address-of operator (&): Returns the memory address of its
operand. Contents-of (Dereference) operator(*): Returns the value of the variable located at the
address specified by its operator.
The asterisk (*) is used in declaring a pointer for simple purpose of indicating that it is a pointer.
Don't confuse this with the dereference operator, which is used to obtain the value located at the
specified address. They are simply two different things represented with the same sign.
Pointer Arithmetic
Increment / Decrement
A pointer can be incremented or decremented (prefix and postfix). Incrementing a pointer
https://riptutorial.com/ 469
advances the pointer value to the element in the array one element past the currently pointed to
element. Decrementing a pointer moves it to the previous element in the array.
Pointer arithmetic is not permitted if the type that the pointer points to is not complete. void is
always an incomplete type.
If a pointer to the end element is incremented, then the pointer points to one element past the end
of the array. Such a pointer cannot be dereferenced, but it can be decremented.
A pointer to a non-array object can be treated, for the purposes of pointer arithmetic, as though it
were an array of size 1.
Addition / Subtraction
Integer values can be added to pointers; they act as incrementing, but by a specific number rather
than by 1. Integer values can be subtracted from pointers as well, acting as pointer decrementing.
As with incrementing/decrementing, the pointer must point to a complete type.
Pointer Differencing
The difference between two pointers to the same type can be computed. The two pointers must be
within the same array object; otherwise undefined behavior results.
Given two pointers P and Q in the same array, if P is the ith element in the array, and Q is the jth
element, then P - Q shall be i - j. The type of the result is std::ptrdiff_t, from <cstddef>.
https://riptutorial.com/ 470
Read Pointers online: https://riptutorial.com/cplusplus/topic/3056/pointers
https://riptutorial.com/ 471
Chapter 82: Pointers to members
Syntax
• Assuming a class named Class...
• For pointers to non-static class members, given the following two definitions:
○ Class instance;
○ Class *p = &instance;
Examples
Pointers to static member functions
A static member function is just like an ordinary C/C++ function, except with scope:
• It is inside a class, so it needs its name decorated with the class name;
• It has accessibility, with public, protected or private.
So, if you have access to the static member function and decorate it correctly, then you can point
to the function like any normal function outside a class:
typedef int Fn(int); // Fn is a type-of function that accepts an int and returns an int
class Class {
public:
// Note that Static() is of type 'Fn'
static int Static(int i) { return 3*i; }
}; // Class
https://riptutorial.com/ 472
int main() {
Fn *fn; // fn is a pointer to a type-of Fn
To access a member function of a class, you need to have a "handle" to the particular instance, as
either the instance itself, or a pointer or reference to it. Given a class instance, you can point to
various of its members with a pointer-to-member, IF you get the syntax correct! Of course, the
pointer has to be declared to be of the same type as what you are pointing to...
typedef int Fn(int); // Fn is a type-of function that accepts an int and returns an int
class Class {
public:
// Note that A() is of type 'Fn'
int A(int a) { return 2*a; }
// Note that B() is of type 'Fn'
int B(int b) { return 3*b; }
}; // Class
int main() {
Class c; // Need a Class instance to play with
Class *p = &c; // Need a Class pointer to play with
Unlike pointers to member variables (in the previous example), the association between the class
instance and the member pointer need to be bound tightly together with parentheses, which looks
a little strange (as though the .* and ->* aren't strange enough!)
To access a member of a class, you need to have a "handle" to the particular instance, as either
the instance itself, or a pointer or reference to it. Given a class instance, you can point to various
of its members with a pointer-to-member, IF you get the syntax correct! Of course, the pointer has
to be declared to be of the same type as what you are pointing to...
class Class {
public:
int x, y, z;
char m, n, o;
}; // Class
https://riptutorial.com/ 473
int x; // Global variable
int main() {
Class c; // Need a Class instance to play with
Class *p = &c; // Need a Class pointer to play with
• To define the type of the pointer, you need to mention the base type, as well as the fact that
it is inside a class: int Class::*ptr;.
• If you have a class or reference and want to use it with a pointer-to-member, you need to
use the .* operator (akin to the . operator).
• If you have a pointer to a class and want to use it with a pointer-to-member, you need to use
the ->* operator (akin to the -> operator).
A static member variable is just like an ordinary C/C++ variable, except with scope:
• It is inside a class, so it needs its name decorated with the class name;
• It has accessibility, with public, protected or private.
So, if you have access to the static member variable and decorate it correctly, then you can point
to the variable like any normal variable outside a class:
class Class {
public:
static int i;
}; // Class
int main() {
int k = 3; // Local variable
https://riptutorial.com/ 474
int *p;
p = &k; // Point to k
*p = 2; // Modify it
p = &j; // Point to j
*p = 3; // Modify it
p = &Class::i; // Point to Class::i
*p = 4; // Modify it
} // main()
https://riptutorial.com/ 475
Chapter 83: Polymorphism
Examples
Define polymorphic classes
The typical example is an abstract shape class, that can then be derived into squares, circles, and
other concrete shapes.
class Shape {
public:
virtual ~Shape() = default;
virtual double get_surface() const = 0;
virtual void describe_object() const { std::cout << "this is a shape" << std::endl; }
• You can define polymorphic behavior by introduced member functions with the keyword
virtual. Here get_surface() and describe_object() will obviously be implemented differently
for a square than for a circle. When the function is invoked on an object, function
corresponding to the real class of the object will be determined at runtime.
• It makes no sense to define get_surface() for an abstract shape. This is why the function is
followed by = 0. This means that the function is pure virtual function.
• You may define non virtual member functions. When these function will be invoked for an
object, the function will be chosen depending on the class used at compile-time. Here
get_double_surface() is defined in this way.
• A class that contains at least one pure virtual function is an abstract class. Abstract classes
cannot be instantiated. You may only have pointers or references of an abstract class type.
Derived classes
Once a polymorphic base class is defined you can derive it. For example:
https://riptutorial.com/ 476
Square (const Point& top_left, double side)
: top_left(top_left), side_length(side_length) {}
Some explanations:
• You can define or override any of the virtual functions of the parent class. The fact that a
function was virtual in the parent class makes it virtual in the derived class. No need to tell
the compiler the keyword virtual again. But it's recommended to add the keyword override
at the end of the function declaration, in order to prevent subtle bugs caused by unnoticed
variations in the function signature.
• If all the pure virtual functions of the parent class are defined you can instantiate objects for
this class, else it will also become an abstract class.
• You are not obliged to override all the virtual functions. You can keep the version of the
parent if it suits your need.
Example of instantiation
int main() {
Square square(Point(10.0, 0.0), 6); // we know it's a square, the compiler also
square.describe_object();
std::cout << "Surface: " << square.get_surface() << std::endl;
Shape *ps = nullptr; // we don't know yet the real type of the object
ps = &circle; // it's a circle, but it could as well be a square
ps->describe_object();
std::cout << "Surface: " << ps->get_surface() << std::endl;
}
Safe downcasting
a downcast would be to cast from a general polymorphic Shape down to one of its derived and
more specific shape like Square or Circle.
Why to downcast ?
Most of the time, you would not need to know which is the real type of the object, as the virtual
https://riptutorial.com/ 477
functions allow you to manipulate your object independently of its type:
However, you may need sometimes to downcast. A typical example is when you want to invoke a
non virtual function that exist only for the child class.
Consider for example circles. Only circles have a diameter. So the class would be defined as :
class Circle: public Shape { // for Shape, see example on defining a polymorphic class
Point center;
double radius;
public:
Circle (const Point& center, double radius)
: center(center), radius(radius) {}
The get_diameter() member function only exist for circles. It was not defined for a Shape object:
Shape* ps = get_any_shape();
ps->get_diameter(); // OUCH !!! Compilation error
How to downcast ?
If you'd know for sure that ps points to a circle you could opt for a static_cast:
This will do the trick. But it's very risky: if ps appears to by anything else than a Circle the behavior
of your code will be undefined.
So rather than playing Russian roulette, you should safely use a dynamic_cast. This is specifically
for polymorphic classes :
int main() {
Circle circle(Point(0.0, 0.0), 10);
Shape &shape = circle;
std::cout << "The shape has a surface of " << shape.get_surface() << std::endl;
https://riptutorial.com/ 478
std::cout << "The shape isn't a circle !" << std::endl;
}
Note that dynamic_cast is not possible on a class that is not polymorphic. You'd need at least one
virtual function in the class or its parents to be able to use it.
If a class is intended to be used polymorphically, with derived instances being stored as base
pointers/references, its base class' destructor should be either virtual or protected. In the former
case, this will cause object destruction to check the vtable, automatically calling the correct
destructor based on the dynamic type. In the latter case, destroying the object through a base
class pointer/reference is disabled, and the object can only be deleted when explicitly treated as
its actual type.
struct VirtualDestructor {
virtual ~VirtualDestructor() = default;
};
struct ProtectedDestructor {
protected:
~ProtectedDestructor() = default;
};
// ...
Both of these practices guarantee that the derived class' destructor will always be called on
derived class instances, preventing memory leaks.
https://riptutorial.com/ 479
Chapter 84: Preprocessor
Introduction
The C preprocessor is a simple text parser/replacer that is run before the actual compilation of the
code. Used to extend and ease the use of the C (and later C++) language, it can be used for:
Remarks
Preprocessor statements are executed before your source files are handed to the compiler. They
are capable of very low level conditional logic. Since preprocessor constructs (e.g. object-like
macros) aren't typed like normal functions (the preprocessing step happens before compilation)
the compiler cannot enforce type checks, they should therefore be carefully used.
Examples
Include Guards
A header file may be included by other header files. A source file (compilation unit) that includes
multiple headers may therefore, indirectly, include some headers more than once. If such a header
file that is included more than once contains definitions, the compiler (after preprocessing) detects
a violation of the One Definition Rule (e.g. §3.2 of the 2003 C++ standard) and therefore issues a
diagnostic and compilation fails.
Multiple inclusion is prevented using "include guards", which are sometimes also known as header
guards or macro guards. These are implemented using the preprocessor #define, #ifndef, #endif
directives.
e.g.
// Foo.h
#ifndef FOO_H_INCLUDED
#define FOO_H_INCLUDED
#endif
https://riptutorial.com/ 480
The key advantage of using include guards is that they will work with all standard-compliant
compilers and preprocessors.
However, include guards also cause some problems for developers, as it is necessary to ensure
the macros are unique within all headers used in a project. Specifically, if two (or more) headers
use FOO_H_INCLUDED as their include guard, the first of those headers included in a compilation unit
will effectively prevent the others from being included. Particular challenges are introduced if a
project uses a number of third-party libraries with header files that happen to use include guards in
common.
It is also necessary to ensure that the macros used in include guards do not conflict with any other
macros defined in header files.
Most C++ implementations also support the #pragma once directive which ensures the file is only
included once within a single compilation. This is a de facto standard directive, but it is not part of
any ISO C++ standard. For example:
// Foo.h
#pragma once
class Foo
{
};
While #pragma once avoids some problems associated with include guards, a #pragma - by definition
in the standards - is inherently a compiler-specific hook, and will be silently ignored by compilers
that don't support it. Projects which use #pragma once are more difficult to port to compilers that
don't support it.
A number of coding guidelines and assurance standards for C++ specifically discourage any use
of the preprocessor other than to #include header files or for the purposes of placing include
guards in headers.
• different app profiles (e.g. debug, release, testing, optimised) that can be candidates of the
same app (e.g. with extra logging).
• cross-platform compiles - single code-base, multiple compilation platforms.
• utilising a common code-base for multiple application versions (e.g. Basic, Premium and
Pro versions of a software) - with slightly different features.
#ifdef _WIN32
#include <windows.h> // and other windows system files
https://riptutorial.com/ 481
#endif
#include <cstdio>
void s_PrintAppStateOnUserPrompt()
{
std::cout << "--------BEGIN-DUMP---------------\n"
<< AppState::Instance()->Settings().ToString() << "\n"
#if ( 1 == TESTING_MODE ) //privacy: we want user details only when testing
<< ListToString(AppState::UndoStack()->GetActionNames())
<< AppState::Instance()->CrntDocument().Name()
<< AppState::Instance()->CrntDocument().SignatureSHA() << "\n"
#endif
<< "--------END-DUMP---------------\n"
}
Example c: Enable a premium feature in a separate product build (note: this is illustrative. it is
often a better idea to allow a feature to be unlocked without the need to reinstall an application)
void MainWindow::OnProcessButtonClick()
{
#ifndef _PREMIUM
CreatePurchaseDialog("Buy App Premium", "This feature is available for our App Premium
users. Click the Buy button to purchase the Premium version at our website");
return;
#endif
//...actual feature logic here
}
The preprocessor can be called with predefined symbols (with optional initialisation). For example
this command (gcc -E runs only the preprocessor)
https://riptutorial.com/ 482
processes Sample.cpp in the same way as it would if #define OPTIMISE_FOR_OS_X and #define
TESTING_MODE 1 were added to the top of Sample.cpp.
If a macro isn't defined and its value is compared or checked, the preprocessor almost always
silently assumes the value to be 0. There are a few ways to work with this. One approach is to
assume that the default settings are represented as 0, and any changes (e.g. to the app build
profile) needs to be explicitly done (e.g. ENABLE_EXTRA_DEBUGGING=0 by default, set -
DENABLE_EXTRA_DEBUGGING=1 to override). Another approach is make all definitions and
defaults explicit. This can be achieved using a combination of #ifndef and #error directives:
#ifndef (ENABLE_EXTRA_DEBUGGING)
// please include DefaultDefines.h if not already included.
# error "ENABLE_EXTRA_DEBUGGING is not defined"
#else
# if ( 1 == ENABLE_EXTRA_DEBUGGING )
//code
# endif
#endif
Macros
Macros are categorized into two main groups: object-like macros and function-like macros. Macros
are treated as a token substitution early in the compilation process. This means that large (or
repeating) sections of code can be abstracted into a preprocessor macro.
The Qt library makes use of this technique to create a meta-object system by having the user
declare the Q_OBJECT macro at the head of the user-defined class extending QObject.
Macro names are usually written in all caps, to make them easier to differentiate from normal
code. This isn't a requirement, but is merely considered good style by many programmers.
When an object-like macro is encountered, it's expanded as a simple copy-paste operation, with
the macro's name being replaced with its definition. When a function-like macro is encountered,
both its name and its parameters are expanded.
https://riptutorial.com/ 483
double pi_squared = PI * PI;
// Compiler sees:
double pi_squared = 3.14159265358979 * 3.14159265358979;
Due to this, function-like macro parameters are often enclosed within parentheses, as in AREA()
above. This is to prevent any bugs that can occur during macro expansion, specifically bugs
caused by a single macro parameter being composed of multiple actual values.
#define BAD_AREA(r) PI * r * r
Also note that due to this simple expansion, care must be taken with the parameters passed to
macros, to prevent unexpected side effects. If the parameter is modified during evaluation, it will
be modified each time it is used in the expanded macro, which usually isn't what we want. This is
true even if the macro encloses the parameters in parentheses to prevent expansion from
breaking anything.
int oops = 5;
double incremental_damage = AREA(oops++);
// Compiler sees:
double incremental_damage = (3.14159265358979*(oops++)*(oops++));
As programmers normally terminate lines with a semicolon, macros that are intended to be used
as standalone lines are often designed to "swallow" a semicolon; this prevents any unintended
bugs from being caused by an extra semicolon.
if (some_condition)
// Oops.
IF_BREAKER(some_func);
else
std::cout << "I am accidentally an orphan." << std::endl;
In this example, the inadvertent double semicolon breaks the if...else block, preventing the
compiler from matching the else to the if. To prevent this, the semicolon is omitted from the macro
definition, which will cause it to "swallow" the semicolon immediately following any usage of it.
https://riptutorial.com/ 484
#define IF_FIXER(Func) Func()
if (some_condition)
IF_FIXER(some_func);
else
std::cout << "Hooray! I work again!" << std::endl;
Leaving off the trailing semicolon also allows the macro to be used without ending the current
statement, which can be beneficial.
// ...
Normally, a macro definition ends at the end of the line. If a macro needs to cover multiple lines,
however, a backslash can be used at the end of a line to indicate this. This backslash must be the
last character in the line, which indicates to the preprocessor that the following line should be
concatenated onto the current line, treating them as a single line. This can be used multiple times
in a row.
// ...
This is especially useful in complex function-like macros, which may need to cover multiple lines.
#define CREATE_OUTPUT_AND_DELETE(Str) \
std::string* tmp = new std::string(Str); \
std::cout << *tmp << std::endl; \
delete tmp;
// ...
In the case of more complex function-like macros, it can be useful to give them their own scope to
prevent possible name collisions or to cause objects to be destroyed at the end of the macro,
similar to an actual function. A common idiom for this is do while 0, where the macro is enclosed in
a do-while block. This block is generally not followed with a semicolon, allowing it to swallow a
semicolon.
https://riptutorial.com/ 485
} while (0)
int x;
DO_STUFF(MyClass, 41153.7, x);
// Compiler sees:
int x;
do {
MyClass temp(some_setup_values);
x = temp.process(41153.7);
} while (0);
There are also variadic macros; similarly to variadic functions, these take a variable number of
arguments, and then expand them all in place of a special "Varargs" parameter, __VA_ARGS__.
Note that during expansion, __VA_ARGS__ can be placed anywhere in the definition, and will be
expanded correctly.
VARIADIC2(some_func, 3, 8, 6, 9);
// Compiler sees:
some_func(8, 6, 9, 3);
In the case of a zero-argument variadic parameter, different compilers will handle the trailing
comma differently. Some compilers, such as Visual Studio, will silently swallow the comma without
any special syntax. Other compilers, such as GCC, require you to place ## immediately before
__VA_ARGS__. Due to this, it is wise to conditionally define variadic macros when portability is a
concern.
// In this example, COMPILER is a user-defined macro specifying the compiler being used.
Compile errors can be generated using the preprocessor. This is useful for a number of reasons
some of which include, notifying a user if they are on an unsupported platform or an unsupported
compiler.
https://riptutorial.com/ 486
#if __GNUC__ < 3
#error "This code requires gcc > 3.0.0"
#endif
#ifdef __APPLE__
#error "Apple products are not supported in this release"
#endif
Predefined macros
Predefined macros are those that the compiler defines (in contrast to those user defines in the
source file). Those macros must not be re-defined or undefined by user.
• __LINE__ contains the line number of the line this macro is used on, and can be changed by
the #line directive.
• __FILE__ contains the filename of the file this macro is used in, and can be changed by the
#line directive.
• __DATE__ contains date (in "Mmm dd yyyy" format) of the file compilation, where Mmm is
formatted as if obtained by a call to std::asctime().
• __TIME__ contains time (in "hh:mm:ss" format) of the file compilation.
• __cplusplus is defined by (conformant) C++ compilers while compiling C++ files. Its value is
the standard version the compiler is fully conformant with, i.e. 199711L for C++98 and C++03,
201103L for C++11 and 201402L for C++14 standard.
c++11
c++17
Additionally, the following macros are allowed to be predefined by implementations, and may or
may not be present:
c++11
https://riptutorial.com/ 487
character set might not be equal to the values of their wide counterparts (e.g. if
(uintmax_t)'x' != (uintmax_t)L'x')
• __STDC_ISO_10646__ is defined if wchar_t is encoded as Unicode, and expands to an integer
constant in the form yyyymmL, indicating the latest Unicode revision supported.
• __STDCPP_STRICT_POINTER_SAFETY__ is defined to 1, if the implementation has strict pointer
safety (otherwise it has relaxed pointer safety)
• __STDCPP_THREADS__ is defined to 1, if the program can have more than one thread of execution
(applicable to freestanding implementation — hosted implementations can always have
more than one thread)
It is also worth mentioning __func__, which is not an macro, but a predefined function-local
variable. It contains the name of the function it is used in, as a static character array in an
implementation-defined format.
On top of those standard predefined macros, compilers can have their own set of predefined
macros. One must refer to the compiler documentation to learn those. E.g.:
• gcc
• Microsoft Visual C++
• clang
• Intel C++ Compiler
c++11
https://riptutorial.com/ 488
std::cout << "Hello World!\n";
}
}
X-macros
An X-macro consists of two parts: the list, and the execution of the list.
Example:
#define LIST \
X(dog) \
X(cat) \
X(racoon)
// class Animal {
// public:
// void say();
// };
int main() {
#define X(name) name.say();
LIST
#undef X
return 0;
}
Animal dog;
Animal cat;
Animal racoon;
int main() {
dog.say();
cat.say();
racoon.say();
return 0;
}
As lists become bigger (let's say, more than 100 elements), this technique helps to avoid
excessive copy-pasting.
Source: https://en.wikipedia.org/wiki/X_Macro
https://riptutorial.com/ 489
If defining a seamingly irrelevant X before using LIST is not to your liking, you can pass a macro
name as an argument as well:
#define LIST(MACRO) \
MACRO(dog) \
MACRO(cat) \
MACRO(racoon)
Now, you explicitly specify which macro should be used when expanding the list, e.g.
If each invocation of the MACRO should take additional parameters - constant with respect to the list,
variadic macros can be used
The first argument is supplied by the LIST, while the rest is provided by the user in the LIST
invocation. For example:
will expand to
Animal anim_dog;
Animal anim_cat;
Animal anim_racoon;
Object obj_dog;
Object obj_cat;
Object obj_racoon;
#pragma once
Most, but not all, C++ implementations support the #pragma once directive which ensures the file is
only included once within a single compilation. It is not part of any ISO C++ standard. For
example:
// Foo.h
#pragma once
class Foo
{
https://riptutorial.com/ 490
};
While #pragma once avoids some problems associated with include guards, a #pragma - by definition
in the standards - is inherently a compiler-specific hook, and will be silently ignored by compilers
that don't support it. Projects which use #pragma once must be modified to be standard-compliant.
With some compilers - particularly those that employ precompiled headers - #pragma once can
result in a considerable speedup of the compilation process. Similarly, some preprocessors
achieve speedup of compilation by tracking which headers have employed include guards. The
net benefit, when both #pragma once and include guards are employed, depends on the
implementation and can be either an increase or decrease of compilation times.
#pragma once combined with include guards was the recommended layout for header files when
writing MFC based applications on windows, and was generated by Visual Studio’s add class, add
dialog, add windows wizards. Hence it is very common to find them combined in C++ Windows
Applicants.
Preprocessor Operators
#operator or stringizing operator is used to convert a Macro parameter to a string literal. It can
only be used with the Macros having arguments.
Compiler concatenate two strings and the final printf() argument will be a string literal with
newline character at its end.
Preprocessor will ignore the spaces before or after the macro argument. So below print statement
will give us the same result.
If the parameter of the string literal requires an escape sequence like before a double quote() it will
automatically be inserted by the preprocessor.
https://riptutorial.com/ 491
#define PRINT(x) printf("variable" #x " = %d", variable##x)
variableY = 15
https://riptutorial.com/ 492
Chapter 85: Profiling
Examples
Profiling with gcc and gprof
The GNU gprof profiler, gprof, allows you to profile your code. To use it, you need to perform the
following steps:
In order to build the application with settings for generating profiling information, we add the -pg
flag. So, for example, we could use
or
and so forth.
$ ./app
(note that we provide both the application as well as the generated output).
and so forth.
The result of the last command should be a table, whose rows are the functions, and whose
columns indicate the number of calls, total time spent, self time spent (that is, time spent in the
https://riptutorial.com/ 493
function excluding calls to children).
For more complex applications, flat execution profiles may be difficult to follow. This is why many
profiling tools also generate some form of annotated callgraph information.
gperf2dot converts text output from many profilers (Linux perf, callgrind, oprofile etc.) into a
callgraph diagram. You can use it by running your profiler (example for gprof):
https://riptutorial.com/ 494
Profiling CPU Usage with gcc and Google Perf Tools
https://riptutorial.com/ 495
Google Perf Tools also provides a CPU profiler, with a slightly friendlier interface. To use it:
For example:
# compile code
g++ -O3 -std=c++11 main.cpp -o main
where:
https://riptutorial.com/ 496
2.19/stdlib/random_r.c:371
1 1.5% 98.5% 1 1.5% __random_r /build/eglibc-3GlaMS/eglibc-
2.19/stdlib/random_r.c:381
1 1.5% 100.0% 1 1.5% rand /build/eglibc-3GlaMS/eglibc-2.19/stdlib/rand.c:28
0 0.0% 100.0% 67 100.0% __libc_start_main /build/eglibc-3GlaMS/eglibc-
2.19/csu/libc-start.c:287
0 0.0% 100.0% 67 100.0% _start ??:0
0 0.0% 100.0% 67 100.0% main ??:0
0 0.0% 100.0% 14 20.9% rand /build/eglibc-3GlaMS/eglibc-2.19/stdlib/rand.c:27
0 0.0% 100.0% 27 40.3% std::vector::_M_emplace_back_aux ??:0
https://riptutorial.com/ 497
Chapter 86: RAII: Resource Acquisition Is
Initialization
Remarks
RAII stands for Resource Acquisition Is Initialization. Also occasionally referred to as SBRM
(Scope-Based Resource Management) or RRID (Resource Release Is Destruction), RAII is an
idiom used to tie resources to object lifetime. In C++, the destructor for an object always runs
when an object goes out of scope - we can take advantage of that to tie resource cleanup into
object destruction.
Any time you need to acquire some resource (e.g. a lock, a file handle, an allocated buffer) that
you will eventually need to release, you should consider using an object to handle that resource
management for you. Stack unwinding will happen regardless of exception or early scope exit, so
the resource handler object will clean up the resource for you without you having to carefully
consider all possible current and future code paths.
It's worth noting that RAII doesn't completely free the developer of thinking about the lifetime of
resources. One case is, obviously, a crash or exit() call, which will prevent destructors from being
called. Since the OS will clean up process-local resources like memory after a process ends, this
is not a problem in most cases. However with system resources (i.e. named pipes, lock files,
shared memory) you still need facilities to deal with the case where a process didn't clean up after
itself, i.e. on startup test if the lock file is there, if it is, verify the process with the pid actually exists,
then act accordingly.
Another situation is when a unix process calls a function from the exec-family, i.e. after a fork-exec
to create a new process. Here, the child process will have a full copy of the parents memory
(including the RAII objects) but once exec was called, none of the destructors will be called in that
process. On the other hand, if a process is forked and neither of the processes call exec, all
resources are cleaned up in both processes. This is correct only for all resources that were
actually duplicated in the fork, but with system resources, both processes will only have a
reference to the resource (i.e. the path to a lock file) and will both try to release it individually,
potentially causing the other process to fail.
Examples
Locking
Bad locking:
std::mutex mtx;
void bad_lock_example() {
mtx.lock();
try
https://riptutorial.com/ 498
{
foo();
bar();
if (baz()) {
mtx.unlock(); // Have to unlock on each exit point.
return;
}
quux();
mtx.unlock(); // Normal unlock happens here.
}
catch(...) {
mtx.unlock(); // Must also force unlock in the presence of
throw; // exceptions and allow the exception to continue.
}
}
That is the wrong way to implement the locking and unlocking of the mutex. To ensure the correct
release of the mutex with unlock() requires the programer to make sure that all the flows resulting
in the exiting of the function result in a call to unlock(). As shown above this is a brittle processes
as it requires any maintainers to continue following the pattern manually.
std::mutex mtx;
void good_lock_example() {
std::lock_guard<std::mutex> lk(mtx); // constructor locks.
// destructor unlocks. destructor call
// guaranteed by language.
foo();
bar();
if (baz()) {
return;
}
quux();
}
lock_guard is an extremely simple class template that simply calls lock() on its argument in its
constructor, keeps a reference to the argument, and calls unlock() on the argument in its
destructor. That is, when the lock_guard goes out of scope, the mutex is guaranteed to be unlocked.
It doesn't matter if the reason it went out of scope is an exception or an early return - all cases are
handled; regardless of the control flow, we have guaranteed that we will unlock correctly.
Finally/ScopeExit
For cases when we don't want to write special classes to handle some resource, we may write a
generic class:
template<typename Function>
class Finally final
{
public:
explicit Finally(Function f) : f(std::move(f)) {}
~Finally() { f(); } // (1) See below
https://riptutorial.com/ 499
Finally(const Finally&) = delete;
Finally(Finally&&) = default;
Finally& operator =(const Finally&) = delete;
Finally& operator =(Finally&&) = delete;
private:
Function f;
};
// Execute the function f when the returned object goes out of scope.
template<typename Function>
auto onExit(Function &&f) { return Finally<std::decay_t<Function>>{std::forward<Function>(f)};
}
v[i] += 42;
auto autoRollBackChange = onExit([&](){ v[i] -= 42; });
Note (1): Some discussion about destructor definition has to be considered to handle exception:
ScopeSuccess (c++17)
C++17
#include <exception>
#include <iostream>
https://riptutorial.com/ 500
// f() might throw, as it can be caught normally.
~ScopeSuccess() noexcept(noexcept(f())) {
if (uncaughtExceptionCount == std::uncaught_exceptions()) {
f();
}
}
};
struct Foo {
~Foo() {
try {
ScopeSuccess logSuccess{[](){std::cout << "Success 1\n";}};
// Scope succeeds,
// even if Foo is destroyed during stack unwinding
// (so when 0 < std::uncaught_exceptions())
// (or previously std::uncaught_exception() == true)
} catch (...) {
}
try {
ScopeSuccess logSuccess{[](){std::cout << "Success 2\n";}};
};
int main()
{
try {
Foo foo;
Output:
Success 1
ScopeFail (c++17)
C++17
Thanks to int std::uncaught_exceptions(), we can implement action which executes only on failure
(thrown exception in scope). Previously bool std::uncaught_exception() just allows to detect if any
stack unwinding is running.
#include <exception>
#include <iostream>
https://riptutorial.com/ 501
private:
F f;
int uncaughtExceptionCount = std::uncaught_exceptions();
public:
explicit ScopeFail(const F& f) : f(f) {}
ScopeFail(const ScopeFail&) = delete;
ScopeFail& operator =(const ScopeFail&) = delete;
struct Foo {
~Foo() {
try {
ScopeFail logFailure{[](){std::cout << "Fail 1\n";}};
// Scope succeeds,
// even if Foo is destroyed during stack unwinding
// (so when 0 < std::uncaught_exceptions())
// (or previously std::uncaught_exception() == true)
} catch (...) {
}
try {
ScopeFail logFailure{[](){std::cout << "Failure 2\n";}};
};
int main()
{
try {
Foo foo;
Output:
Failure 2
https://riptutorial.com/ 502
Chapter 87: Random number generation
Remarks
Random number generation in C++ is provided by the <random> header. This header defines
random devices, pseudo-random generators and distributions.
Random devices return random numbers provided by operating system. They should either be
used for initialization of pseudo-random generators or directly for cryptographic purposes.
Pseudo-random generators return integer pseudo-random numbers based on their initial seed.
The pseudo-random number range typically spans all values of an unsigned type. All pseudo-
random generators in the standard library will return the same numbers for the same initial seed
for all platforms.
Distributions consume random numbers from pseudo-random generators or random devices and
produce random numbers with necessary distribution. Distributions are not platform-independent
and can produce different numbers for the same generators with the same initial seeds on
different platforms.
Examples
True random value generator
To generate true random values that can be used for cryptography std::random_device has to be
used as generator.
#include <iostream>
#include <random>
int main()
{
std::random_device crypto_random_generator;
std::uniform_int_distribution<int> int_distribution(0,9);
return 0;
}
std::random_device is used in the same way as a pseudo random value generator is used.
https://riptutorial.com/ 503
However std::random_device may be implemented in terms of an implementation-defined
pseudo-random number engine if a non-deterministic source (e.g. a hardware device) isn't
available to the implementation.
Detecting such implementations should be possible via the entropy member function (which return
zero when the generator is completely deterministic), but many popular libraries (both GCC's
libstdc++ and LLVM's libc++) always return zero, even when they're using high-quality external
randomness.
A pseudo-random number generator generates values that can be guessed based on previously
generated values. In other words: it is deterministic. Do not use a pseudo-random number
generator in situations where a true random number is required.
#include <iostream>
#include <random>
int main()
{
std::default_random_engine pseudo_random_generator;
std::uniform_int_distribution<int> int_distribution(0, 9);
return 0;
}
This code creates a random number generator, and a distribution that generates integers in the
range [0,9] with equal likelihood. It then counts how many times each result was generated.
The random number generator can (and should) be used for multiple distributions.
#include <iostream>
#include <random>
int main()
{
std::default_random_engine pseudo_random_generator;
https://riptutorial.com/ 504
std::uniform_int_distribution<int> int_distribution(0, 9);
std::uniform_real_distribution<float> float_distribution(0.0, 1.0);
std::discrete_distribution<int> rigged_dice({1,1,1,1,1,100});
return 0;
}
In this example, only one generator is defined. It is subsequently used to generate a random value
in three different distributions. The rigged_dice distribution will generate a value between 0 and 5,
but almost always generates a 5, because the chance to generate a 5 is 100 / 105.
https://riptutorial.com/ 505
Chapter 88: Recursion in C++
Examples
Using tail recursion and Fibonnaci-style recursion to solve the Fibonnaci
sequence
The simple and most obvious way to use recursion to get the Nth term of the Fibonnaci sequence
is this
int get_term_fib(int n)
{
if (n == 0)
return 0;
if (n == 1)
return 1;
return get_term_fib(n - 1) + get_term_fib(n - 2);
}
However, this algorithm does not scale for higher terms: for bigger and bigger n, the number of
function calls that you need to make grows exponentially. This can be replaced with a simple tail
recursion.
Each call to the function now immediately calculates the next term in the Fibonnaci sequence, so
the number of function calls scales linearly with n.
Recursive functions can get quite expensive. If they are pure functions (functions that always
return the same value when called with the same arguments, and that neither depend on nor
modify external state), they can be made considerably faster at the expense of memory by storing
the values already calculated.
#include <map>
int fibonacci(int n)
{
static std::map<int, int> values;
https://riptutorial.com/ 506
if (n==0 || n==1)
return n;
std::map<int,int>::iterator iter = values.find(n);
if (iter == values.end())
{
return values[n] = fibonacci(n-1) + fibonacci(n-2);
}
else
{
return iter->second;
}
}
Note that despite using the simple recursion formula, on first call this function is $O(n)$. On
subsequent calls with the same value, it is of course $O(1)$.
Note however that this implementation is not reentrant. Also, it doesn't allow to get rid of stored
values. An alternative implementation would be to allow the map to be passed as additional
argument:
#include <map>
For this version, the caller is required to maintain the map with the stored values. This has the
advantage that the function is now reentrant, and that the caller can remove values that are no
longer needed, saving memory. It has the disadvantage that it breaks encapsulation; the caller can
change the output by populating the map with incorrect values.
https://riptutorial.com/ 507
Chapter 89: Recursive Mutex
Examples
std::recursive_mutex
Recursive mutex allows the same thread to recursively lock a resource - up to an unspecified limit.
There are very few real-word justifications for this. Certain complex implementations might need to
call an overloaded copy of a function without releasing the lock.
std::atomic_int temp{0};
std::recursive_mutex _mutex;
std::this_thread::sleep_for(std::chrono::seconds(3));
std::unique_lock<std::recursive_mutex> lock( _mutex);
temp=0;
});
}
});
future1.get();
future2.get();
https://riptutorial.com/ 508
Chapter 90: Refactoring Techniques
Introduction
Refactoring refers to the modification of existing code into an improved version. Although
refactoring is often done while changing code to add features or fix bugs, the term particularly
refers improving code without necessarily adding features or fixing bugs.
Examples
Refactoring walk through
Here's a program which might benefit from refactoring. It's a simple program using C++11 which is
intended to calculate and print all prime numbers from 1 to 100 and is based on a program that
was posted on CodeReview for review.
#include <iostream>
#include <vector>
#include <cmath>
int main()
{
int l = 100;
bool isprime;
std::vector<int> primes;
primes.push_back(2);
for (int no = 3; no < l; no += 2) {
isprime = true;
for (int primecount=0; primes[primecount] <= std::sqrt(no); ++primecount) {
if (no % primes[primecount] == 0) {
isprime = false;
break;
} else if (primes[primecount] * primes[primecount] > no) {
std::cout << no << "\n";
break;
}
}
if (isprime) {
std::cout << no << " ";
primes.push_back(no);
}
}
std::cout << "\n";
}
3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
The first thing we notice is that the program fails to print 2 which is a prime number. We could
simply add a line of code to simply print that one constant without modifying the rest of the
https://riptutorial.com/ 509
program, but it might be neater to refactor the program to split it into two parts - one that creates
the prime number list an another that prints them. Here's how that might look:
#include <iostream>
#include <vector>
#include <cmath>
int main()
{
std::vector<int> primes = prime_list(100);
for (std::size_t i = 0; i < primes.size(); ++i) {
std::cout << primes[i] << ' ';
}
std::cout << '\n';
}
Trying this version, we see that it does indeed work correctly now:
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
The next step is to notice that the second if clause is not really needed. The logic in the loop
looks for prime factors of each given number up to the square root of that number. This works
because if there are any prime factors of a number at least one of them must be less than or equal
to the square root of that number. Reworking just that function (the rest of the program remains
the same) we get this result:
https://riptutorial.com/ 510
isprime = false;
break;
}
}
if (isprime) {
primes.push_back(no);
}
}
return primes;
}
We can go further, changing variable names to be a bit more descriptive. For example primecount
isn't really a count of primes. Instead it's an index variable into the vector of known primes. Also,
while no is sometimes used as an abbreviation for "number", in mathematical writing, it's more
common to use n. We can also make some modifications by eliminating the break, and by
declaring variables closer to where they're used.
int main()
{
std::vector<int> primes = prime_list(100);
for (auto p : primes) {
std::cout << p << ' ';
}
std::cout << '\n';
}
This is just one way refactoring might be done. Others might make different choices. However, the
purpose for refactoring remains the same, which is to improve the readability and possibly the
performance of the code without necessarily adding features.
Goto Cleanup
In C++ code bases which used to be C, one can find the pattern goto cleanup. As the goto
command makes the workflow of a function harder to understand, this is often avoided. Often, it
can be replaced by return statements, loops, functions. Though, with the goto cleanup one needs
to get rid of cleanup logic.
https://riptutorial.com/ 511
short calculate(VectorStr **data) {
short result = FALSE;
VectorStr *vec = NULL;
if (!data)
goto cleanup; //< Could become return false
result = TRUE;
cleanup:
delete [] vec;
return result;
}
return TRUE;
}
From this point on, one could continue refactoring the actual code. For example by replacing the
VectorRAII by std::unique_ptr or std::vector.
https://riptutorial.com/ 512
Chapter 91: References
Examples
Defining a reference
References behaves similarly, but not entirely like const pointers. A reference is defined by
suffixing an ampersand & to a type name.
int i = 10;
int &refi = i;
// Common pitfall :
// int& refi = i, k = j;
// refi will be of type int&.
// though, k will be of type int, not int&!
References must be initialized correctly at the time of definition, and cannot be modified
afterwards. The following piece of codes causes a compile error:
A Reference in C++ is just an Alias or another name of a variable. Just like most of us can be
referred using our passport name and nick name.
References doesn't exist literally and they don't occupy any memory. If we print the address of
reference variable it will print the same address as that of the variable its referring to.
int main() {
https://riptutorial.com/ 513
int i = 10;
int &j = i;
cout<<&i<<endl;
cout<<&b<<endl;
return 0;
}
In the above example, both cout will print the same address. The situation will be same if we take
a variable as a reference in a function
int main() {
int i = 10;
cout<<"Address inside Main => "<<&i<<endl;
func(i);
return 0;
}
In this example also, both cout will print the same address.
As we know by now that C++ References are just alias, and for an alias to be created, we need to
have something which the Alias can refer to.
That's the precise reason why the statement like this will throw a compiler error
int &i;
https://riptutorial.com/ 514
Chapter 92: Regular expressions
Introduction
Regular Expressions (sometimes called regexs or regexps) are a textual syntax which represents
the patterns which can be matched in the strings operated upon.
Regular Expressions, introduced in c++11, may optionally support a return array of matched
strings or another textual syntax defining how to replace matched patterns in strings operated
upon.
Syntax
• regex_match // Returns whether the entire character sequence was matched by the regex,
optionally capturing into a match object
• regex_search // Returns whether a portion of the character sequence was matched by the
regex, optionally capturing into a match object
• regex_replace // Returns the input character sequence as modified by a regex via a
replacement format string
• regex_token_iterator // Initialized with a character sequence defined by iterators, a list of
capture indexes to iterate over, and a regex. Dereferencing returns the currently indexed
match of the regex. Incrementing moves to the next capture index or if currently at the last
index, resets the index and hinds the next occurrence of a regex match in the character
sequence
• regex_iterator // Initialized with a character sequence defined by iterators and a regex.
Dereferencing returns the portion of the character sequence the entire regex currently
matches. Incrementing finds the next occurrence of a regex match in the character sequence
Parameters
Signature Description
https://riptutorial.com/ 515
Signature Description
Examples
Basic regex_match and regex_search Examples
const auto input = "Some people, when confronted with a problem, think \"I know, I'll use
regular expressions.\""s;
smatch sm;
// If input ends in a quotation that contains a word that begins with "reg" and another word
begining with "ex" then capture the preceeding portion of input
if (regex_match(input, sm, regex("(.*)\".*\\breg.*\\bex.*\"\\s*$"))) {
const auto capture = sm[1].str();
cout << '\t' << capture << endl; // Outputs: "\tSome people, when confronted with a
problem, think\n"
cout << '\t' << count << (count > 1 ? " problems\n" : " problem\n"); // Outputs: "\t1
problem\n"
cout << "Now they have " << count + 1 << " problems.\n"; // Ouputs: "Now they have 2
problems\n"
}
}
Live Example
regex_replace Example
This code takes in various brace styles and converts them to One True Brace Style:
Live Example
https://riptutorial.com/ 516
regex_token_iterator Example
Live Example
A notable gotcha with regex iterators is, that the regex argument must be an L-value. An R-value
will not work.
regex_iterator Example
enum TOKENS {
NUMBER,
ADDITION,
SUBTRACTION,
MULTIPLICATION,
DIVISION,
EQUALITY,
OPEN_PARENTHESIS,
CLOSE_PARENTHESIS
};
We can tokenize this string: const auto input = "42/2 + -8\t=\n(2 + 2) * 2 * 2 -3"s with a
regex_iterator like this:
vector<TOKENS> tokens;
const regex re{ "\\s*(\\(?)\\s*(-?\\s*\\d+)\\s*(\\)?)\\s*(?:(\\+)|(-)|(\\*)|(/)|(=))" };
if(i[3].length() > 0) {
tokens.push_back(CLOSE_PARENTHESIS);
}
https://riptutorial.com/ 517
auto it = next(cbegin(i), 4);
match_results<string::const_reverse_iterator> sm;
Live Example
A notable gotcha with regex iterators is that the regex argument must be an L-value, an R-value
will not work: Visual Studio regex_iterator Bug?
Splitting a string
split("Some string\t with whitespace ", "\\s+"); // "Some", "string", "with", "whitespace"
Quantifiers
Let's say that we're given const string input as a phone number to be validated. We could start by
requiring a numeric input with a zero or more quantifier: regex_match(input, regex("\\d*")) or a
one or more quantifier: regex_match(input, regex("\\d+")) But both of those really fall short if
input contains an invalid numeric string like: "123" Let's use a n or more quantifier to ensure that
we're getting at least 7 digits:
regex_match(input, regex("\\d{7,}"))
This will guarantee that we will get at least a phone number of digits, but input could also contain a
numeric string that's too long like: "123456789012". So lets go with a between n and m
quantifier so the input is at least 7 digits but not more than 11:
regex_match(input, regex("\\d{7,11}"));
This gets us closer, but illegal numeric strings that are in the range of [7, 11] are still accepted,
https://riptutorial.com/ 518
like: "123456789" So let's make the country code optional with a lazy quantifier:
regex_match(input, regex("\\d?\\d{7,10}"))
It's important to note that the lazy quantifier matches as few characters as possible, so the only
way this character will be matched is if there are already 10 characters that have been matched by
\d{7,10}. (To match the first character greedily we would have had to do: \d{0,1}.) The lazy
quantifier can be appended to any other quantifier.
Now, how would we make the area code optional and only accept a country code if the area code
was present?
regex_match(input, regex("(?:\\d{3,4})?\\d{7}"))
In this final regex, the \d{7} requires 7 digits. These 7 digits are optionally preceded by either 3 or
4 digits.
Note that we did not append the lazy quantifier: \d{3,4}?\d{7}, the \d{3,4}? would have matched
either 3 or 4 characters, preferring 3. Instead we're making the non-capturing group match at most
once, preferring not to match. Causing a mismatch if input didn't include the area code like:
"1234567".
In conclusion of the quantifier topic, I'd like to mention the other appending quantifier that you can
use, the possessive quantifier. Either the lazy quantifier or the possessive quantifier can be
appended to any quantifier. The possessive quantifier's only function is to assist the regex
engine by telling it, greedily take these characters and don't ever give them up even if it causes
the regex to fail. This for example doesn't make much sense: regex_match(input,
regex("\\d{3,4}+\\d{7})) Because an input like: "1234567890" wouldn't be matched as \d{3,4}+
will always match 4 characters even if matching 3 would have allowed the regex to succeed.
The possessive quantifier is best used when the quantified token limits the number of matchable
characters. For example:
regex_match(input, regex("(?:.*\\d{3,4}+){3}"))
But when this regex really shines is when input contains an illegal input:
12345 - 67890
Without the possessive quantifier the regex engine has to go back and test every combination of
.* and either 3 or 4 characters to see if it can find a matchable combination. With the possessive
https://riptutorial.com/ 519
quantifier the regex starts where the 2nd possessive quantifier left off, the '0' character, and the
regex engine tries to adjust the .* to allow \d{3,4} to match; when it can't the regex just fails, no
back tracking is done to see if earlier .* adjustment could have allowed a match.
Anchors
Let's say for example we want to capture a number with it's sign:
do {
cout << sm[1] << endl;
input = sm.suffix().str();
} while(regex_search(input, sm, regex{ "(?:^\\W|\\b\\W)([+-]?\\d+)" }));
}
Live Example
An important note here is that the anchor does not consume any characters.
https://riptutorial.com/ 520
Chapter 93: Resource Management
Introduction
One of the hardest things to do in C and C++ is resource management. Thankfully, in C++, we
have many ways to go about designing resource management in our programs. This article hopes
to explain some of the idioms and methods used to manage allocated resources.
Examples
Resource Acquisition Is Initialization
#include <memory>
#include <iostream>
using namespace std;
int main() {
{
auto_ptr ap(new int(5)); // dynamic memory is the resource
cout << *ap << endl; // prints 5
} // auto_ptr is destroyed, its resource is automatically freed
}
C++11
#include <memory>
#include <iostream>
using namespace std;
int main() {
auto_ptr ap1(new int(5));
cout << *ap1 << endl; // prints 5
auto_ptr ap2(ap1); // copy ap2 from ap1; ownership now transfers to ap2
cout << *ap2 << endl; // prints 5
cout << ap1 == nullptr << endl; // prints 1; ap1 has lost ownership of resource
}
Because of these weird copy semantics, std::auto_ptr can't be used in containers, among other
things. The reason it does this is to prevent deleting memory twice: if there are two auto_ptrs with
ownership of the same resource, they both try to free it when they're destroyed. Freeing an
https://riptutorial.com/ 521
already freed resource can generally cause problems, so it is important to prevent it. However,
std::shared_ptr has a method to avoid this while not transferring ownership when copying:
#include <memory>
#include <iostream>
using namespace std;
int main() {
shared_ptr sp2;
{
shared_ptr sp1(new int(5)); // give ownership to sp1
cout << *sp1 << endl; // prints 5
sp2 = sp1; // copy sp2 from sp1; both have ownership of resource
cout << *sp1 << endl; // prints 5
cout << *sp2 << endl; // prints 5
} // sp1 goes out of scope and is destroyed; sp2 has sole ownership of resource
cout << *sp2 << endl;
} // sp2 goes out of scope; nothing has ownership, so resource is freed
Problems may happen when multiple threads try to access a resource. For a simple example,
suppose we have a thread that adds one to a variable. It does this by first reading the variable,
adding one to it, then storing it back. Suppose we initialize this variable to 1, then create two
instances of this thread. After both threads finish, intuition suggests that this variable should have
a value of 3. However, the below table illustrates what might go wrong:
Thread 1 Thread 2
As you can see, at the end of the operation, 2 is in the variable, instead of 3. The reason is that
Thread 2 read the variable before Thread 1 was done updating it. The solution? Mutexes.
https://riptutorial.com/ 522
pandemonium if everybody tried to access the resource at once.
C++11
#include <thread>
#include <mutex>
#include <iostream>
using namespace std;
int main() {
int var = 1;
mutex m;
https://riptutorial.com/ 523
Chapter 94: Return Type Covariance
Remarks
Covariance of a parameter or a return value for a virtual member function m is where its type T
gets more specific in a derived class' override of m. The type T then varies (variance) in specificity
in the same way (co) as the classes providing m. C++ provides language support for covariant
return types that are raw pointers or raw references – the covariance is for the pointee or referent
type.
The C++ support is limited to return types because function return values are the only pure out-
arguments in C++, and covariance is only type safe for a pure out-argument. Otherwise calling
code could supply an object of less specific type than the receiving code expects. MIT professor
Barbara Liskov investigated this and related variance type safety issues, and it's now known as
the Liskov Substitution Principle, or LSP.
The covariance support essentially helps to avoid downcasting and dynamic type checking.
Since smart pointers are of class type one cannot use the built-in support for covariance directly
for smart pointer results, but one can define apparently covariant non-virtual smart pointer result
wrapper functions for a covariant virtual function that produces raw pointers.
Examples
1. Base example without covariant returns, shows why they're desirable
// 1. Base example not using language support for covariance, dynamic type checking.
class Top
{
public:
virtual Top* clone() const = 0;
virtual ~Top() = default; // Necessary for `delete` via Top*.
};
public:
Top* clone() const override
{ return new D( *this ); }
};
class DD : public D
{
private:
int answer_ = 42;
public:
int answer() const
https://riptutorial.com/ 524
{ return answer_;}
#include <assert.h>
#include <iostream>
#include <typeinfo>
using namespace std;
int main()
{
cout << boolalpha;
class Top
{
public:
virtual Top* clone() const = 0;
virtual ~Top() = default; // Necessary for `delete` via Top*.
};
class DD : public D
{
private:
int answer_ = 42;
public:
int answer() const
{ return answer_;}
#include <iostream>
https://riptutorial.com/ 525
using namespace std;
int main()
{
DD* p1 = new DD();
DD* p2 = p1->clone();
// Correct dynamic type DD for *p2 is guaranteed by the static type checking.
#include <memory>
using std::unique_ptr;
class Top
{
private:
virtual Top* virtual_clone() const = 0;
public:
unique_ptr<Top> clone() const
{ return up( virtual_clone() ); }
public:
unique_ptr<D> /* ← Apparent covariant return */ clone() const
{ return up( virtual_clone() ); }
};
class DD : public D
{
private:
int answer_ = 42;
public:
int answer() const
{ return answer_;}
https://riptutorial.com/ 526
{ return up( virtual_clone() ); }
};
#include <iostream>
using namespace std;
int main()
{
auto p1 = unique_ptr<DD>(new DD());
auto p2 = p1->clone();
// Correct dynamic type DD for *p2 is guaranteed by the static type checking.
https://riptutorial.com/ 527
Chapter 95: Returning several values from a
function
Introduction
There are many situations where it is useful to return several values from a function: for example,
if you want to input an item and return the price and number in stock, this functionality could be
useful. There are many ways to do this in C++, and most involve the STL. However, if you wish to
avoid the STL for some reason, there are still several ways to do this, including structs/classes
and arrays.
Examples
Using Output Parameters
Parameters can be used for returning one or more values; those parameters are required to be
non-const pointers or references.
References:
Pointers:
Some libraries or frameworks use an empty 'OUT' #define to make it abundantly obvious which
parameters are output parameters in the function signature. This has no functional impact, and will
be compiled out, but makes the function signature a bit clearer;
#define OUT
https://riptutorial.com/ 528
Using std::tuple
C++11
The type std::tuple can bundle any number of values, potentially including values of different
types, into a single return object:
C++17
Retrieving values from the returned tuple can be cumbersome, requiring the use of the std::get
template function:
If the types can be declared before the function returns, then std::tie can be employed to unpack
a tuple into existing variables:
C++17
If you want to return a tuple of lvalue references instead of a tuple of values, use std::tie in place
of std::make_tuple.
https://riptutorial.com/ 529
else
return std::tie(a,b);
}
which permits
In some rare cases you'll use std::forward_as_tuple instead of std::tie; be careful if you do so, as
temporaries may not last long enough to be consumed.
Using std::array
C++11
The container std::array can bundle together a fixed number of return values. This number has to
be known at compile-time and all return values have to be of the same type:
This replaces c style arrays of the form int bar[4]. The advantage being that various c++ std
functions can now be used on it. It also provides useful member functions like at which is a safe
member access function with bound checking, and size which allows you to return the size of the
array without calculation.
Using std::pair
The struct template std::pair can bundle together exactly two return values, of any two types:
#include <utility>
std::pair<int, int> foo(int a, int b) {
return std::make_pair(a+b, a-b);
}
C++11
#include <utility>
std::pair<int, int> foo(int a, int b) {
return {a+b, a-b};
}
The individual values of the returned std::pair can be retrieved by using the pair's first and
second member objects:
https://riptutorial.com/ 530
std::pair<int, int> mrvs = foo(5, 12);
std::cout << mrvs.first + mrvs.second << std::endl;
Output:
10
Using struct
C++11
struct foo_return_type {
int add;
int sub;
int mul;
int div;
};
C++11
Instead of assignment to individual fields, a constructor can be used to simplify the constructing of
returned values:
struct foo_return_type {
int add;
int sub;
int mul;
int div;
foo_return_type(int add, int sub, int mul, int div)
: add(add), sub(sub), mul(mul), div(div) {}
};
The individual results returned by the function foo() can be retrieved by accessing the member
variables of the struct calc:
std::cout << calc.add << ' ' << calc.sub << ' ' << calc.mul << ' ' << calc.div << '\n';
Output:
17 -7 60 0
https://riptutorial.com/ 531
Note: When using a struct, the returned values are grouped together in a single object and
accessible using meaningful names. This also helps to reduce the number of extraneous variables
created in the scope of the returned values.
C++17
In order to unpack a struct returned from a function, structured bindings can be used. This places
the out-parameters on an even footing with the in-parameters:
The output of this code is identical to that above. The struct is still used to return the values from
the function. This permits you do deal with the fields individually.
Structured Bindings
C++17
C++17 introduces structured bindings, which makes it even easier to deal with multiple return
types, as you do not need to rely upon std::tie() or do any manual tuple unpacking:
std::map<std::string, int> m;
if (success) {
// your code goes here
}
// iterate over all elements without having to use the cryptic 'first' and 'second' names
for (auto const& [key, value] : m) {
std::cout << "The value for " << key << " is " << value << '\n';
}
Structured bindings can be used by default with std::pair, std::tuple, and any type whose non-
static data members are all either public direct members or members of an unambiguous base
class:
struct A { int x; };
struct B : A { int y; };
B foo();
https://riptutorial.com/ 532
If you make your type "tuple-like" it will also automatically work with your type. A tuple-like is a type
with appropriate tuple_size, tuple_element and get written:
namespace my_ns {
struct my_type {
int x;
double d;
std::string s;
};
struct my_type_view {
my_type* ptr;
};
}
namespace std {
template<>
struct tuple_size<my_ns::my_type_view> : std::integral_constant<std::size_t, 3>
{};
namespace my_ns {
template<std::size_t I>
decltype(auto) get(my_type_view const& v) {
if constexpr (I == 0)
return v.ptr->x;
else if constexpr (I == 1)
return v.ptr->d;
else if constexpr (I == 2)
return v.ptr->s;
static_assert(I < 3, "Only 3 elements");
}
}
my_ns::my_type_view foo() {
return {&t};
}
int main() {
auto[x, d, s] = foo();
std::cout << x << ',' << d << ',' << s << '\n';
}
We can provide a consumer that will be called with the multiple relevant values:
C++11
https://riptutorial.com/ 533
void foo(int a, int b, F consumer) {
consumer(a + b, a - b, a * b, a / b);
}
You can adapt a function returning a tuple into a continuation passing style function via:
C++17
template<class Tuple>
struct continuation {
Tuple t;
template<class F>
decltype(auto) operator->*(F&& f)&&{
return std::apply( std::forward<F>(f), std::move(t) );
}
};
std::tuple<int,int,int,int> foo(int a, int b);
Using std::vector
A std::vector can be useful for returning a dynamic number of variables of the same type. The
following example uses int as data type, but a std::vector can hold any type that is trivially
copyable:
#include <vector>
#include <iostream>
// the following function returns all integers between and including 'a' and 'b' in a vector
// (the function can return up to std::vector::max_size elements with the vector, given that
// the system's main memory can hold that many items)
std::vector<int> fillVectorFrom(int a, int b) {
std::vector<int> temp;
for (int i = a; i <= b; i++) {
temp.push_back(i);
}
return temp;
}
int main() {
// assigns the filled vector created inside the function to the new vector 'v'
std::vector<int> v = fillVectorFrom(1, 10);
https://riptutorial.com/ 534
for (int i = 0; i < v.size(); i++) {
std::cout << v[i] << " ";
}
std::cout << std::endl;
return 0;
}
Several values of the same type can be returned by passing an output iterator to the function. This
is particularly common for generic functions (like the algorithms of the standard library).
Example:
Example usage:
std::vector<int> digits;
generate_sequence(0, 10, std::back_inserter(digits));
// digits now contains {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
https://riptutorial.com/ 535
Chapter 96: RTTI: Run-Time Type Information
Examples
Name of a type
You can retrieve the implementation defined name of a type in runtime by using the .name()
member function of the std::type_info object returned by typeid.
#include <iostream>
#include <typeinfo>
int main()
{
int speed = 110;
Output (implementation-defined):
int
dynamic_cast
Use dynamic_cast<>() as a function, which helps you to cast down through an inheritance hierarchy
(main description).
If you must do some non-polymorphic work on some derived classes B and C, but received the
base class A, then write like this:
class B: public A
{ public: void work4B(){} };
class C: public A
{ public: void work4C(){} };
The typeid keyword is a unary operator that yields run-time type information about its operand if
https://riptutorial.com/ 536
the operand's type is a polymorphic class type. It returns an lvalue of type const std::type_info.
Top-level cv-qualification are ignored.
struct Base {
virtual ~Base() = default;
};
struct Derived : Base {};
Base* b = new Derived;
assert(typeid(*b) == typeid(Derived{})); // OK
typeid can also be applied to a type directly. In this case, first top-level references are stripped,
then top-level cv-qualification is ignored. Thus, the above example could have been written with
typeid(Derived) instead of typeid(Derived{}):
assert(typeid(*b) == typeid(Derived{})); // OK
If typeid is applied to any expression that is not of polymorphic class type, the operand is not
evaluated, and the type info returned is for the static type.
struct Base {
// note: no virtual destructor
};
struct Derived : Base {};
Derived d;
Base& b = d;
assert(typeid(b) == typeid(Base)); // not Derived
assert(typeid(std::declval<Base>()) == typeid(Base)); // OK because unevaluated
Use reinterpret_cast for low-level reinterpreting of bit patterns. Use with extreme caution.
Use const_cast for casting away const/volatile. Avoid this unless you are stuck using a const-
incorrect API.
https://riptutorial.com/ 537
Chapter 97: Scopes
Examples
Simple block scope
The scope of a variable in a block { ... }, begins after declaration and ends at the end of the
block. If there is nested block, the inner block can hide the scope of a variable which is declared in
the outer block.
{
int x = 100;
// ^
// Scope of `x` begins here
//
} // <- Scope of `x` ends here
If a nested block starts within an outer block, a new declared variable with the same name which is
before in the outer class, hides the first one.
{
int x = 100;
{
int x = 200;
Global variables
To declare a single instance of a variable which is accessible in different source files, it is possible
to make it in the global scope with keyword extern. This keyword says the compiler that
somewhere in the code there is a definition for this variable, so it can be used everywhere and all
write/read will be done in one place of memory.
// File my_globals.h:
#ifndef __MY_GLOBALS_H__
#define __MY_GLOBALS_H__
#endif
https://riptutorial.com/ 538
// File foo1.cpp:
#include "my_globals.h"
// File main.cpp:
#include "my_globals.h"
#include <iostream>
int main()
{
std::cout << "The radius is: " << circle_radius << "\n";'
return 0;
}
Output:
https://riptutorial.com/ 539
Chapter 98: Semaphore
Introduction
Semaphores are not available in C++ as of now, but can easily be implemented with a mutex and
a condition variable.
Examples
Semaphore C++ 11
#include <mutex>
#include <condition_variable>
class Semaphore {
public:
Semaphore (int count_ = 0)
: count(count_)
{
}
The following function adds four threads. Three threads compete for the semaphore, which is set
to a count of one. A slower thread calls notify_one(), allowing one of the waiting threads to
https://riptutorial.com/ 540
proceed.
The result is that s1 immediately starts spinning, causing the Semaphore's usage count to remain
below 1. The other threads wait in turn on the condition variable until notify() is called.
int main()
{
Semaphore sem(1);
thread s1([&]() {
while(true) {
this_thread::sleep_for(std::chrono::seconds(5));
sem.wait( 1 );
}
});
thread s2([&]() {
while(true){
sem.wait( 2 );
}
});
thread s3([&]() {
while(true) {
this_thread::sleep_for(std::chrono::milliseconds(600));
sem.wait( 3 );
}
});
thread s4([&]() {
while(true) {
this_thread::sleep_for(std::chrono::seconds(5));
sem.notify( 4 );
}
});
s1.join();
s2.join();
s3.join();
s4.join();
...
}
https://riptutorial.com/ 541
Chapter 99: SFINAE (Substitution Failure Is
Not An Error)
Examples
enable_if
std::enable_if is a convenient utility to use boolean conditions to trigger SFINAE. It is defined as:
That is, enable_if<true, R>::type is an alias for R, whereas enable_if<false, T>::type is ill-formed
as that specialization of enable_if does not have a type member type.
Here, a call to negate(1) would fail due to ambiguity. But the second overload is not intended to be
used for integral types, so we can add:
When to use it
It's worth keeping in mind that std::enable_if is a helper on top of SFINAE, but it's not what makes
SFINAE work in the first place. Let's consider these two alternatives for implementing functionality
similar to std::size, i.e. an overload set size(arg) that produces the size of a container or array:
https://riptutorial.com/ 542
// for containers
template<typename Cont>
auto size1(Cont const& cont) -> decltype( cont.size() );
// for arrays
template<typename Elt, std::size_t Size>
std::size_t size1(Elt const(&arr)[Size]);
// implementation omitted
template<typename Cont>
struct is_sizeable;
// for containers
template<typename Cont, std::enable_if_t<std::is_sizeable<Cont>::value, int> = 0>
auto size2(Cont const& cont);
// for arrays
template<typename Elt, std::size_t Size>
std::size_t size2(Elt const(&arr)[Size]);
Assuming that is_sizeable is written appropriately, these two declarations should be exactly
equivalent with respect to SFINAE. Which is the easiest to write, and which is the easiest to review
and understand at a glance?
Now let's consider how we might want to implement arithmetic helpers that avoid signed integer
overflow in favour of wrap around or modular behaviour. Which is to say that e.g. incr(i, 3) would
be the same as i += 3 save for the fact that the result would always be defined even if i is an int
with value INT_MAX. These are two possible alternatives:
Once again which is the easiest to write, and which is the easiest to review and understand at a
glance?
https://riptutorial.com/ 543
void_t
C++11
void_t is a meta-function that maps any (number of) types to type void. The primary purpose of
void_t is to facilitate writing of type traits.
std::void_t will be part of C++17, but until then, it is extremely straightforward to implement:
template <class...>
struct make_void { using type = void; };
The primary application of void_t is writing type traits that check validity of a statement. For
example, let's check if a type has a member function foo() that takes no arguments:
How does this work? When I try to instantiate has_foo<T>::value, that will cause the compiler to try
to look for the best specialization for has_foo<T, void>. We have two options: the primary, and this
secondary one which involves having to instantiate that underlying expression:
• If T does have a member function foo(), then whatever type that returns gets converted to
void, and the specialization is preferred to the primary based on the template partial ordering
rules. So has_foo<T>::value will be true
• If T doesn't have such a member function (or it requires more than one argument), then
substitution fails for the specialization and we only have the primary template to fallback on.
Hence, has_foo<T>::value is false.
A simpler case:
template<class T, class=void>
struct can_reference : std::false_type {};
template<class T>
struct can_reference<T, std::void_t<T&>> : std::true_type {};
You may notice a common pattern of a void argument. We can factor this out:
https://riptutorial.com/ 544
struct details {
template<template<class...>class Z, class=void, class...Ts>
struct can_apply:
std::false_type
{};
template<template<class...>class Z, class...Ts>
struct can_apply<Z, std::void_t<Z<Ts...>>, Ts...>:
std::true_type
{};
};
template<template<class...>class Z, class...Ts>
using can_apply = details::can_apply<Z, void, Ts...>;
which hides the use of std::void_t and makes can_apply act like an indicator whether the type
supplied as the first template argument is well-formed after substituting the other types into it. The
previous examples may now be rewritten using can_apply as:
template<class T>
using ref_t = T&;
template<class T>
using can_reference = can_apply<ref_t, T>; // Is T& well formed for T?
and:
template<class T>
using dot_foo_r = decltype(std::declval<T&>().foo());
template<class T>
using can_dot_foo = can_apply< dot_foo_r, T >; // Is T.foo() well formed for T?
The utility of void_t was discovered by Walter Brown. He gave a wonderful presentation on it at
CppCon 2016.
C++11
One of constraining function is to use trailing decltype to specify the return type:
namespace details {
using std::to_string;
https://riptutorial.com/ 545
}
// this one is unconstrained, but less preferred due to the ellipsis argument
template <class T>
std::string convert_to_string(T const& val, ... )
{
std::ostringstream oss;
oss << val;
return oss.str();
}
}
If I call convert_to_string() with an argument with which I can invoke to_string(), then I have two
viable functions for details::convert_to_string(). The first is preferred since the conversion from 0
to int is a better implicit conversion sequence than the conversion from 0 to ...
If I call convert_to_string() with an argument from which I cannot invoke to_string(), then the first
function template instantiation leads to substitution failure (there is no decltype(to_string(val))).
As a result, that candidate is removed from the overload set. The second function template is
unconstrained, so it is selected and we instead go through operator<<(std::ostream&, T). If that
one is undefined, then we have a hard compile error with a template stack on the line oss << val.
What is SFINAE
SFINAE stands for Substitution Failure Is Not An Error. Ill-formed code that results from
substituting types (or values) to instantiate a function template or a class template is not a hard
compile error, it is only treated as a deduction failure.
Deduction failures on instantiating function templates or class template specializations remove that
candidate from the set of consideration - as if that failed candidate did not exist to begin with.
int vals[10];
begin(vals); // OK. The first function template substitution fails because
// vals.begin() is ill-formed. This is not an error! That function
// is just removed from consideration as a viable overload candidate,
// leaving us with the array overload.
Only substitution failures in the immediate context are considered deduction failures, all others
are considered hard errors.
https://riptutorial.com/ 546
void add_one(T& val) { val += 1; }
int i = 4;
add_one(i); // ok
enable_if_all / enable_if_any
C++11
Motivational example
When you have a variadic template pack in the template parameters list, like in the following code
snippet:
The standard library (prior to C++17) offers no direct way to write enable_if to impose SFINAE
constraints on all of the parameters in Args or any of the parameters in Args. C++17 offers
std::conjunction and std::disjunction which solve this problem. For example:
If you do not have C++17 available, there are several solutions to achieve these. One of them is to
use a base-case class and partial specializations, as demonstrated in answers of this question.
Alternatively, one may also implement by hand the behavior of std::conjunction and
std::disjunction in a rather straight-forward way. In the following example I'll demonstrate the
implementations and combine them with std::enable_if to produce two alias: enable_if_all and
enable_if_any, which do exactly what they are supposed to semantically. This may provide a more
scalable solution.
First let's emulate std::conjunction and std::disjunction using customized seq_and and seq_or
respectively:
https://riptutorial.com/ 547
/// Helper for prior to C++14.
template<bool B, class T, class F >
using conditional_t = typename std::conditional<B,T,F>::type;
template<bool... Bs>
using enable_if_any = std::enable_if<seq_or<Bs...>::value>;
template<bool... Bs>
using enable_if_all = std::enable_if<seq_and<Bs...>::value>;
template<bool... Bs>
using enable_if_any_t = typename enable_if_any<Bs...>::type;
template<bool... Bs>
using enable_if_all_t = typename enable_if_all<Bs...>::type;
Usage
is_detected
With template parameters typename Default, template <typename...> Op and typename ... Args:
https://riptutorial.com/ 548
• is_detected: alias of std::true_type or std::false_type depending of the validity of Op<Args...>
• detected_t: alias of Op<Args...> or nonesuch depending of validity of Op<Args...>.
• detected_or: alias of a struct with value_t which is is_detected, and type which is Op<Args...>
or Default depending of validity of Op<Args...>
C++17
namespace detail {
template <class Default, class AlwaysVoid,
template<class...> class Op, class... Args>
struct detector
{
using value_t = std::false_type;
using type = Default;
};
} // namespace detail
struct C1 {};
struct C2 {
int foo(char) const;
};
https://riptutorial.com/ 549
static_assert(!has_foo_char<C1>::value, "Unexpected");
static_assert(has_foo_char<C2>::value, "Unexpected");
static_assert(std::is_same<void, // Default
detected_or<void, foo_type, C1, char>>::value,
"Unexpected");
static_assert(std::is_same<int, detected_or<void, foo_type, C2, char>>::value,
"Unexpected");
If you need to select between several options, enabling just one via enable_if<> can be quite
cumbersome, since several conditions needs to be negated too.
The ordering between overloads can instead be selected using inheritance, i.e. tag dispatch.
Instead of testing for the thing that needs to be well-formed, and also testing the negation of all the
other versions conditions, we instead test just for what we need, preferably in a decltype in a
trailing return.
This might leave several option well formed, we differentiate between those using 'tags', similar to
iterator-trait tags (random_access_tag et al). This works because a direct match is better that a base
class, which is better that a base class of a base class, etc.
#include <algorithm>
#include <iterator>
namespace detail
{
// this gives us infinite types, that inherit from each other
template<std::size_t N>
struct pick : pick<N-1> {};
template<>
struct pick<0> {};
https://riptutorial.com/ 550
}
// this is the function the user calls. it will dispatch the call
// to the correct implementation with the help of 'tags'.
template<typename T>
void stable_sort(T& t)
{
// use an N that is higher that any used above.
// this will pick the highest overload that is well formed.
detail::stable_sort(t, detail::pick<10>{});
}
There are other methods commonly used to differentiate between overloads, such as exact match
being better than conversion, being better than ellipsis.
However, tag-dispatch can extend to any number of choices, and is a bit more clear in intent.
https://riptutorial.com/ 551
Chapter 100: Side by Side Comparisons of
classic C++ examples solved via C++ vs
C++11 vs C++14 vs C++17
Examples
Looping through a container
In C++, looping through a sequence container c can be done using indexes as follows:
While simple, such writings are subject to common semantic errors, like wrong comparison
operator, or wrong indexing variable:
Looping can also be achieved for all containers using iterators, with similar drawbacks:
C++11 introduced range-based for loops and auto keyword, allowing the code to become:
for(auto& x : c) x = 0;
Here the only parameters are the container c, and a variable x to hold the current value. This
prevents the semantics errors previously pointed.
In such implementation, the expression auto begin = c.begin(), end = c.end(); forces begin and
end to be of the same type, while end is never incremented, nor dereferenced. So the range-based
for loop only works for containers defined by a pair iterator/iterator. The C++17 standard relaxes
this constraint by changing the implementation to:
https://riptutorial.com/ 552
{
// ...
}
Here begin and end are allowed to be of different types, as long as they can be compared for
inequality. This allows to loop through more containers, e.g. a container defined by a pair
iterator/sentinel.
Read Side by Side Comparisons of classic C++ examples solved via C++ vs C++11 vs C++14 vs
C++17 online: https://riptutorial.com/cplusplus/topic/7134/side-by-side-comparisons-of-classic-
cplusplus-examples-solved-via-cplusplus-vs-cplusplus11-vs-cplusplus14-vs-cplusplus17
https://riptutorial.com/ 553
Chapter 101: Singleton Design Pattern
Remarks
A Singleton is designed to ensure a class only has one instance and provides a global point of
access to it. If you only require one instance or a convenient global point of access, but not both,
consider other options before turning to the singleton.
Global variables can make it harder to reason about code. For example, if one of the calling
functions isn't happy with the data it's receiving from a Singleton, you now have to track down
what is first giving the singleton bad data in the first place.
Singletons also encourage coupling, a term used to describe two components of code that are
joined together thus reducing each components own measure of self-containment.
Singletons aren't concurrency friendly. When a class has a global point of access, every thread
has the ability to access it which can lead to deadlocks and race conditions.
Lastly, lazy initialization can cause performance issues if initialized at the wrong time. Removing
lazy initialization also removes some of the features that do make Singleton's interesting in the first
place, such as polymorphism (see Subclasses).
Examples
Lazy Initialization
This example has been lifted from the Q & A section here:
http://stackoverflow.com/a/1008289/3807729
See this article for a simple design for a lazy evaluated with guaranteed destruction singleton:
Can any one provide me a sample of Singleton in c++?
class S
{
public:
static S& getInstance()
{
static S instance; // Guaranteed to be destroyed.
// Instantiated on first use.
return instance;
}
private:
S() {}; // Constructor? (the {} brackets) are needed here.
// C++ 03
https://riptutorial.com/ 554
// ========
// Dont forget to declare these two. You want to make sure they
// are unacceptable otherwise you may accidentally get copies of
// your singleton appearing.
S(S const&); // Don't Implement
void operator=(S const&); // Don't implement
// C++ 11
// =======
// We can use the better technique of deleting the methods
// we don't want.
public:
S(S const&) = delete;
void operator=(S const&) = delete;
See this two article about initialization order and how to cope:
Static variables initialisation order
Finding C++ static initialization order problems
See this article that explains why double checked locking will not work on C++:
What are all the common undefined behaviours that a C++ programmer should know about?
Subclasses
class API
{
public:
static API& instance();
virtual ~API() {}
protected:
API() {}
API(const API&) = delete;
API& operator=(const API&) = delete;
};
https://riptutorial.com/ 555
class WindowsAPI : public API
{
public:
virtual const char* func1() override { /* Windows code */ }
virtual void func2() override { /* Windows code */ }
};
API& API::instance() {
#if PLATFORM == WIN32
static WindowsAPI instance;
#elif PLATFORM = LINUX
static LinuxAPI instance;
#endif
return instance;
}
In this example, a simple compiler switch binds the API class to the appropriate subclass. In this
way, API can be accessed without being coupled to platform-specific code.
Thread-safe Singeton
C++11
The C++11 standards guarantees that the initialization of function scope objects are initialized in a
synchronized manner. This can be used to implement a thread-safe singleton with lazy
initialization.
class Foo
{
public:
static Foo& instance()
{
static Foo inst;
return inst;
}
private:
Foo() {}
Foo(const Foo&) = delete;
Foo& operator =(const Foo&) = delete;
};
There are times with multiple static objects where you need to be able to guarantee that the
singleton will not be destroyed until all the static objects that use the singleton no longer need it.
In this case std::shared_ptr can be used to keep the singleton alive for all users even when the
static destructors are being called at the end of the program:
https://riptutorial.com/ 556
class Singleton
{
public:
Singleton(Singleton const&) = delete;
Singleton& operator=(Singleton const&) = delete;
private:
Singleton() {}
};
https://riptutorial.com/ 557
Chapter 102: Smart Pointers
Syntax
• std::shared_ptr<ClassType> variableName = std::make_shared<ClassType>(arg1, arg2, ...);
• std::shared_ptr<ClassType> variableName (new ClassType(arg1, arg2, ...));
• std::unique_ptr<ClassType> variableName = std::make_unique<ClassType>(arg1, arg2, ...); //
C++14
• std::unique_ptr<ClassType> variableName (new ClassType(arg1, arg2, ...));
Remarks
C++ is not a memory-managed language. Dynamically allocated memory (i.e. objects created with
new) will be "leaked" if it is not explicitly deallocated (with delete). It is the programmer's
responsibility to ensure that the dynamically allocated memory is freed before discarding the last
pointer to that object.
Smart pointers can be used to automatically manage the scope of dynamically allocated memory
(i.e. when the last pointer reference goes out of scope it is deleted).
Smart pointers are preferred over "raw" pointers in most cases. They make the ownership
semantics of dynamically allocated memory explicit, by communicating in their names whether an
object is intended to be shared or uniquely owned.
Examples
Sharing ownership (std::shared_ptr)
The class template std::shared_ptr defines a shared pointer that is able to share ownership of an
object with other shared pointers. This contrasts to std::unique_ptr which represents exclusive
ownership.
The sharing behavior is implemented through a technique known as reference counting, where the
number of shared pointers that point to the object is stored alongside it. When this count reaches
zero, either through the destruction or reassignment of the last std::shared_ptr instance, the object
is automatically destroyed.
To create multiple smart pointers that share the same object, we need to create another shared_ptr
that aliases the first shared pointer. Here are 2 ways of doing it:
https://riptutorial.com/ 558
std::shared_ptr<Foo> secondShared(firstShared); // 1st way: Copy constructing
std::shared_ptr<Foo> secondShared;
secondShared = firstShared; // 2nd way: Assigning
Either of the above ways makes secondShared a shared pointer that shares ownership of our
instance of Foo with firstShared.
The smart pointer works just like a raw pointer. This means, you can use * to dereference them.
The regular -> operator works as well:
Finally, when the last aliased shared_ptr goes out of scope, the destructor of our Foo instance is
called.
Warning: Constructing a shared_ptr might throw a bad_alloc exception when extra data for shared
ownership semantics needs to be allocated. If the constructor is passed a regular pointer it
assumes to own the object pointed to and calls the deleter if an exception is thrown. This means
shared_ptr<T>(new T(args)) will not leak a T object if allocation of shared_ptr<T> fails. However, it is
advisable to use make_shared<T>(args) or allocate_shared<T>(alloc, args), which enable the
implementation to optimize the memory allocation.
C++11C++17
Specifying std::default_delete is mandatory here to make sure that the allocated memory is
correctly cleaned up using delete[].
template<class Arr>
struct shared_array_maker {};
template<class T, std::size_t N>
struct shared_array_maker<T[N]> {
std::shared_ptr<T> operator()const{
auto r = std::make_shared<std::array<T,N>>();
if (!r) return {};
return {r.data(), r};
}
};
template<class Arr>
https://riptutorial.com/ 559
auto make_shared_array()
-> decltype( shared_array_maker<Arr>{}() )
{ return shared_array_maker<Arr>{}(); }
C++17
With C++17, shared_ptr gained special support for array types. It is no longer necessary to specify
the array-deleter explicitly, and the shared pointer can be dereferenced using the [] array index
operator:
Both p2 and p1 own the object of type Foo, but p2 points to its int member x. This means that if p1
goes out of scope or is reassigned, the underlying Foo object will still be alive, ensuring that p2
does not dangle.
Important: A shared_ptr only knows about itself and all other shared_ptr that were created with the
alias constructor. It does not know about any other pointers, including all other shared_ptrs created
with a reference to the same Foo instance:
By default, shared_ptr increments the reference count and doesn't transfer the ownership.
However, it can be made to transfer the ownership using std::move:
shared_ptr<int> up = make_shared<int>();
// Transferring the ownership
shared_ptr<int> up2 = move(up);
// At this point, the reference count of up = 0 and the
// ownership of the pointer is solely with up2 with reference count = 1
https://riptutorial.com/ 560
Sharing with temporary ownership (std::weak_ptr)
Instances of std::weak_ptr can point to objects owned by instances of std::shared_ptr while only
becoming temporary owners themselves. This means that weak pointers do not alter the object's
reference count and therefore do not prevent an object's deletion if all of the object's shared
pointers are reassigned or destroyed.
In the following example instances of std::weak_ptr are used so that the destruction of a tree
object is not inhibited:
#include <memory>
#include <vector>
struct TreeNode {
std::weak_ptr<TreeNode> parent;
std::vector< std::shared_ptr<TreeNode> > children;
};
int main() {
// Create a TreeNode to serve as the root/parent.
std::shared_ptr<TreeNode> root(new TreeNode);
// Reset the root shared pointer, destroying the root object, and
// subsequently its child nodes.
root.reset();
}
As child nodes are added to the root node's children, their std::weak_ptr member parent is set to
the root node. The member parent is declared as a weak pointer as opposed to a shared pointer
such that the root node's reference count is not incremented. When the root node is reset at the
end of main(), the root is destroyed. Since the only remaining std::shared_ptr references to the
child nodes were contained in the root's collection children, all child nodes are subsequently
destroyed as well.
Due to control block implementation details, shared_ptr allocated memory may not be released
until shared_ptr reference counter and weak_ptr reference counter both reach zero.
#include <memory>
int main()
{
{
std::weak_ptr<int> wk;
{
// std::make_shared is optimized by allocating only once
// while std::shared_ptr<int>(new int(42)) allocates twice.
// Drawback of std::make_shared is that control block is tied to our integer
https://riptutorial.com/ 561
std::shared_ptr<int> sh = std::make_shared<int>(42);
wk = sh;
// sh memory should be released at this point...
}
// ... but wk is still alive and needs access to control block
}
// now memory is released (sh and wk)
}
Since std::weak_ptr does not keep its referenced object alive, direct data access through a
std::weak_ptr is not possible. Instead it provides a lock() member function that attempts to retrieve
a std::shared_ptr to the referenced object:
#include <cassert>
#include <memory>
int main()
{
{
std::weak_ptr<int> wk;
std::shared_ptr<int> sp;
{
std::shared_ptr<int> sh = std::make_shared<int>(42);
wk = sh;
// calling lock will create a shared_ptr to the object referenced by wk
sp = wk.lock();
// sh will be destroyed after this point, but sp is still alive
}
// sp still keeps the data alive.
// At this point we could even call lock() again
// to retrieve another shared_ptr to the same data from wk
assert(*sp == 42);
assert(!wk.expired());
// resetting sp will delete the data,
// as it is currently the last shared_ptr with ownership
sp.reset();
// attempting to lock wk now will return an empty shared_ptr,
// as the data has already been deleted
sp = wk.lock();
assert(!sp);
assert(wk.expired());
}
}
C++11
A std::unique_ptr is a class template that manages the lifetime of a dynamically stored object.
Unlike for std::shared_ptr, the dynamic object is owned by only one instance of a std::unique_ptr
at any time,
https://riptutorial.com/ 562
(Note: std::unique_ptr is available since C++11 and std::make_unique since C++14.)
Only the variable ptr holds a pointer to a dynamically allocated int. When a unique pointer that
owns an object goes out of scope, the owned object is deleted, i.e. its destructor is called if the
object is of class type, and the memory for that object is released.
To use std::unique_ptr and std::make_unique with array-types, use their array specializations:
You can access the std::unique_ptr just like a raw pointer, because it overloads those operators.
You can transfer ownership of the contents of a smart pointer to another pointer by using std::move
, which will cause the original smart pointer to point to nullptr.
// 1. std::unique_ptr
std::unique_ptr<int> ptr = std::make_unique<int>();
// Change value to 1
*ptr = 1;
// 2. std::unique_ptr (by moving 'ptr' to 'ptr2', 'ptr' doesn't own the object anymore)
std::unique_ptr<int> ptr2 = std::move(ptr);
Returning unique_ptr from functions. This is the preferred C++11 way of writing factory functions,
as it clearly conveys the ownership semantics of the return: the caller owns the resulting
unique_ptr and is responsible for it.
std::unique_ptr<int> foo()
{
std::unique_ptr<int> ptr = std::make_unique<int>(59);
return ptr;
}
https://riptutorial.com/ 563
std::unique_ptr<int> ptr = foo();
int* foo_cpp03();
C++14
The class template make_unique is provided since C++14. It's easy to add it manually to C++11
code:
C++11
Unlike the dumb smart pointer (std::auto_ptr), unique_ptr can also be instantiated with vector
allocation (not std::vector). Earlier examples were for scalar allocations. For example to have a
dynamically allocated integer array for 10 elements, you would specify int[] as the template type
(and not just int):
You need not to worry about de-allocation. This template specialized version calls constructors
and destructors appropriately. Using vectored version of unique_ptr or a vector itself - is a personal
choice.
In versions prior to C++11, std::auto_ptr was available. Unlike unique_ptr it is allowed to copy
auto_ptrs, upon which the source ptr will lose the ownership of the contained pointer and the
target receives it.
https://riptutorial.com/ 564
Using custom deleters to create a wrapper to a C interface
Many C interfaces such as SDL2 have their own deletion functions. This means that you cannot
use smart pointers directly:
Instead, you need to define your own deleter. The examples here use the SDL_Surface structure
which should be freed using the SDL_FreeSurface() function, but they should be adaptable to many
other C interfaces.
The deleter must be callable with a pointer argument, and therefore can be e.g. a simple function
pointer:
Any other callable object will work, too, for example a class with an operator():
struct SurfaceDeleter {
void operator()(SDL_Surface* surf) {
SDL_FreeSurface(surf);
}
};
This not only provides you with safe, zero overhead (if you use unique_ptr) automatic memory
management, you also get exception safety.
Note that the deleter is part of the type for unique_ptr, and the implementation can use the empty
base optimization to avoid any change in size for empty custom deleters. So while
std::unique_ptr<SDL_Surface, SurfaceDeleter> and std::unique_ptr<SDL_Surface,
void(*)(SDL_Surface*)> solve the same problem in a similar way, the former type is still only the
size of a pointer while the latter type has to hold two pointers: both the SDL_Surface* and the
function pointer! When having free function custom deleters, it is preferable to wrap the function in
an empty type.
In cases where reference counting is important, one could use a shared_ptr instead of an
unique_ptr. The shared_ptr always stores a deleter, this erases the type of the deleter, which might
be useful in APIs. The disadvantages of using shared_ptr over unique_ptr include a higher memory
cost for storing the deleter and a performance cost for maintaining the reference count.
https://riptutorial.com/ 565
C++17
With template auto, we can make it even easier to wrap our custom deleters:
Here, the purpose of auto is to handle all free functions, whether they return void (e.g.
SDL_FreeSurface) or not (e.g. fclose).
C++11
NOTE: std::auto_ptr has been deprecated in C++11 and will be removed in C++17. You should
only use this if you are forced to use C++03 or earlier and are willing to be careful. It is
recommended to move to unique_ptr in combination with std::move to replace std::auto_ptr
behavior.
As with all smart pointers, std::auto_ptr automatically cleans up resources (see RAII):
{
std::auto_ptr<int> p(new int(42));
std::cout << *p;
} // p is deleted here, no memory leaked
std::auto_ptr<X> px = ...;
std::auto_ptr<X> py = px;
// px is now empty
This allows to use std::auto_ptr to keep ownership explicit and unique at the danger of losing
ownership unintended:
void f(std::auto_ptr<X> ) {
// assumes ownership of X
https://riptutorial.com/ 566
// deletes it at end of scope
};
std::auto_ptr<X> px = ...;
f(px); // f acquires ownership of underlying X
// px is now empty
px->foo(); // NPE!
// px.~auto_ptr() does NOT delete
The transfer of ownership happened in the "copy" constructor. auto_ptr's copy constructor and
copy assignment operator take their operands by non-const reference so that they could be
modified. An example implementation might be:
T* release() {
T* tmp = ptr;
ptr = nullptr;
return tmp;
}
This breaks copy semantics, which require that copying an object leaves you with two equivalent
versions of it. For any copyable type, T, I should be able to write:
T a = ...;
T b(a);
assert(b == a);
But for auto_ptr, this is not the case. As a result, it is not safe to put auto_ptrs in containers.
https://riptutorial.com/ 567
By deriving your class from the class template enable_shared_from_this, you inherit a method
shared_from_this that returns a shared_ptr instance to this.
#include <memory>
class A: public enable_shared_from_this<A> {
};
A* ap1 =new A();
shared_ptr<A> ap2(ap1); // First prepare a shared pointer to the object and hold it!
// Then get a shared pointer to the object from the object itself
shared_ptr<A> ap3 = ap1->shared_from_this();
int c3 =ap3.use_count(); // =2: pointing to the same object
int main()
{
...
auto w = std::make_shared< Widget >();
w -> DoSomething();
...
}
If you use shared_from_this() on an object not owned by a shared_ptr, such as a local automatic
object or a global object, then the behavior is undefined. Since C++17 it throws std::bad_alloc
instead.
https://riptutorial.com/ 568
auto derivedPtr(std::make_shared<Derived>());
auto basePtr(std::static_pointer_cast<Base>(derivedPtr));
auto constBasePtr(std::const_pointer_cast<Base const>(basePtr));
auto constDerivedPtr(std::dynamic_pointer_cast<Derived const>(constBasePtr));
Note that std::reinterpret_pointer_cast is not available in C++11 and C++14, as it was only
proposed by N3920 and adopted into Library Fundamentals TS in February 2014. However, it can
be implemented as follows:
A value_ptr is a smart pointer that behaves like a value. When copied, it copies its contents. When
created, it creates its contents.
// Like std::default_delete:
template<class T>
struct default_copier {
// a copier must handle a null T const* in and return null:
T* operator()(T const* tin)const {
if (!tin) return nullptr;
return new T(*tin);
}
void operator()(void* dest, T const* tin)const {
if (!tin) return;
return new(dest) T(*tin);
}
};
// tag class to handle empty case:
struct empty_ptr_t {};
constexpr empty_ptr_t empty_ptr{};
// the value pointer type itself:
template<class T, class Copier=default_copier<T>, class Deleter=std::default_delete<T>,
class Base=std::unique_ptr<T, Deleter>
>
struct value_ptr:Base, private Copier {
using copier_type=Copier;
// also typedefs from unique_ptr
using Base::Base;
value_ptr( T const& t ):
Base( std::make_unique<T>(t) ),
Copier()
{}
value_ptr( T && t ):
Base( std::make_unique<T>(std::move(t)) ),
Copier()
{}
// almost-never-empty:
value_ptr():
Base( std::make_unique<T>() ),
Copier()
https://riptutorial.com/ 569
{}
value_ptr( empty_ptr_t ) {}
https://riptutorial.com/ 570
// operator-> from unique_ptr
};
template<class T, class...Args>
value_ptr<T> make_value_ptr( Args&&... args ) {
return {std::make_unique<T>(std::forward<Args>(args)...)};
}
This particular value_ptr is only empty if you construct it with empty_ptr_t or if you move from it. It
exposes the fact it is a unique_ptr, so explicit operator bool() const works on it. .get() has been
changed to return a reference (as it is almost never empty), and .get_pointer() returns a pointer
instead.
This smart pointer can be useful for pImpl cases, where we want value-semantics but we also don't
want to expose the contents of the pImpl outside of the implementation file.
With a non-default Copier, it can even handle virtual base classes that know how to produce
instances of their derived and turn them into value-types.
https://riptutorial.com/ 571
Chapter 103: Sorting
Remarks
The std::sort function family is found in the algorithm library.
Examples
Sorting sequence containers with specifed ordering
If the values in a container have certain operators already overloaded, std::sort can be used with
specialized functors to sort in either ascending or descending order:
C++11
#include <vector>
#include <algorithm>
#include <functional>
std::vector<int> v = {5,1,2,4,3};
// Or just:
std::sort(v.begin(), v.end());
//Or just:
std::sort(v.rbegin(), v.rend());
C++14
In C++14, we don't need to provide the template argument for the comparison function objects and
instead let the object deduce based on what it gets passed in:
If no ordering function is passed, std::sort will order the elements by calling operator< on pairs of
elements, which must return a type contextually convertible to bool (or just bool). Basic types
(integers, floats, pointers etc) have already build in comparison operators.
We can overload this operator to make the default sort call work on user-defined types.
https://riptutorial.com/ 572
// Include sequence containers
#include <vector>
#include <deque>
#include <list>
class Base {
public:
int variable;
};
int main() {
std::vector <Base> vector;
std::deque <Base> deque;
std::list <Base> list;
deque.push_back(a);
deque.push_back(b);
list.push_back(a);
list.push_back(b);
return 0;
}
https://riptutorial.com/ 573
// Insert sorting algorithm
#include <algorithm>
class Base {
public:
int variable;
};
int main() {
std::vector <Base> vector;
std::deque <Base> deque;
std::list <Base> list;
deque.push_back(a);
deque.push_back(b);
list.push_back(a);
list.push_back(b);
return 0;
}
C++11
class Base {
https://riptutorial.com/ 574
public:
int variable;
};
int main() {
// Create 2 elements to sort
Base a(10);
Base b(5);
return 0;
}
std::sort,found in the standard library header algorithm, is a standard library algorithm for sorting
a range of values, defined by a pair of iterators. std::sort takes as the last parameter a functor
used to compare two values; this is how it determines the order. Note that std::sort is not stable.
The comparison function must impose a Strict, Weak Ordering on the elements. A simple less-
than (or greater-than) comparison will suffice.
A container with random-access iterators can be sorted using the std::sort algorithm:
C++11
#include <vector>
#include <algorithm>
https://riptutorial.com/ 575
std::sort(MyVector.begin(), MyVector.end());
std::sort requires that its iterators are random access iterators. The sequence containers
std::list and std::forward_list (requiring C++11) do not provide random access iterators, so they
cannot be used with std::sort. However, they do have sort member functions which implement a
sorting algorithm that works with their own iterator types.
C++11
#include <list>
#include <algorithm>
Their member sort functions always sort the entire list, so they cannot sort a sub-range of
elements. However, since list and forward_list have fast splicing operations, you could extract
the elements to be sorted from the list, sort them, then stuff them back where they were quite
efficiently like this:
This example sorts elements in ascending order of a key using a map. You can use any type,
including class, instead of std::string, in the example below.
#include <iostream>
#include <utility>
#include <map>
int main()
{
std::map<double, std::string> sorted_map;
// Sort the names of the planets according to their size
sorted_map.insert(std::make_pair(0.3829, "Mercury"));
sorted_map.insert(std::make_pair(0.9499, "Venus"));
sorted_map.insert(std::make_pair(1, "Earth"));
sorted_map.insert(std::make_pair(0.532, "Mars"));
sorted_map.insert(std::make_pair(10.97, "Jupiter"));
sorted_map.insert(std::make_pair(9.14, "Saturn"));
sorted_map.insert(std::make_pair(3.981, "Uranus"));
sorted_map.insert(std::make_pair(3.865, "Neptune"));
https://riptutorial.com/ 576
for (auto const& entry: sorted_map)
{
std::cout << entry.second << " (" << entry.first << " of Earth's radius)" << '\n';
}
}
Output:
If entries with equal keys are possible, use multimap instead of map (like in the following example).
To sort elements in descending manner, declare the map with a proper comparison functor (
std::greater<>):
#include <iostream>
#include <utility>
#include <map>
int main()
{
std::multimap<int, std::string, std::greater<int>> sorted_map;
// Sort the names of animals in descending order of the number of legs
sorted_map.insert(std::make_pair(6, "bug"));
sorted_map.insert(std::make_pair(4, "cat"));
sorted_map.insert(std::make_pair(100, "centipede"));
sorted_map.insert(std::make_pair(2, "chicken"));
sorted_map.insert(std::make_pair(0, "fish"));
sorted_map.insert(std::make_pair(4, "horse"));
sorted_map.insert(std::make_pair(8, "spider"));
Output
https://riptutorial.com/ 577
Sorting built-in arrays
The sort algorithm sorts a sequence defined by two iterators. This is enough to sort a built-in (also
known as c-style) array.
C++11
Prior to C++11, end of array had to be "calculated" using the size of the array:
C++11
https://riptutorial.com/ 578
Chapter 104: Special Member Functions
Examples
Virtual and Protected Destructors
A class designed to be inherited-from is called a Base class. Care should be taken with the special
member functions of such a class.
A class designed to be used polymorphically at run-time (through a pointer to the base class)
should declare the destructor virtual. This allows the derived parts of the object to be properly
destroyed, even when the object is destroyed through a pointer to the base class.
class Base {
public:
virtual ~Base() = default;
private:
// data members etc.
};
private:
// more data members
};
If the class does not need to be polymorphic, but still needs to allow its interface to be inherited,
use a non-virtual protected destructor.
class NonPolymorphicBase {
public:
// some methods
protected:
~NonPolymorphicBase() = default; // note: non-virtual
private:
// etc.
};
Such a class can never be destroyed through a pointer, avoiding silent leaks due to slicing.
This technique especially applies to classes designed to be private base classes. Such a class
might be used to encapsulate some common implementation details, while providing virtual
https://riptutorial.com/ 579
methods as customisation points. This kind of class should never be used polymorphically, and a
protected destructor helps to document this requirement directly in the code.
Finally, some classes may require that they are never used as a base class. In this case, the class
can be marked final. A normal non-virtual public destructor is fine in this case.
private:
// etc.
};
Bear in mind that declaring a destructor inhibits the compiler from generating implicit move
constructors and move assignment operators. If you declare a destructor, remember to also add
appropriate definitions for the move operations.
Furthermore, declaring move operations will suppress the generation of copy operations, so these
should also be added (if the objects of this class are required to have copy semantics).
class Movable {
public:
virtual ~Movable() noexcept = default;
If you're writing a class that manages resources, you need to implement all the special member
functions (see Rule of Three/Five/Zero). The most direct approach to writing the copy constructor
and assignment operator would be:
https://riptutorial.com/ 580
delete [] name;
name = new char[std::strlen(other.name) + 1];
std::strcpy(name, other.name);
age = other.age;
}
return *this;
}
But this approach has some problems. It fails the strong exception guarantee - if new[] throws,
we've already cleared the resources owned by this and cannot recover. We're duplicating a lot of
the logic of copy construction in copy assignment. And we have to remember the self-assignment
check, which usually just adds overhead to the copy operation, but is still critical.
To satisfy the strong exception guarantee and avoid code duplication (double so with the
subsequent move assignment operator), we can use the copy-and-swap idiom:
class person {
char* name;
int age;
public:
/* all the other functions ... */
swap(lhs.name, rhs.name);
swap(lhs.age, rhs.age);
}
person p1 = ...;
person p2 = ...;
p1 = p2;
First, we copy-construct rhs from p2 (which we didn't have to duplicate here). If that operation
throws, we don't do anything in operator= and p1 remains untouched. Next, we swap the members
between *this and rhs, and then rhs goes out of scope. When operator=, that implicitly cleans the
original resources of this (via the destructor, which we didn't have to duplicate). Self-assignment
works too - it's less efficient with copy-and-swap (involves an extra allocation and deallocation),
but if that's the unlikely scenario, we don't slow down the typical use case to account for it.
C++11
https://riptutorial.com/ 581
p1 = std::move(p2);
Here, we move-construct rhs from p2, and all the rest is just as valid. If a class is movable but not
copyable, there is no need to delete the copy-assignment, since this assignment operator will
simply be ill-formed due to the deleted copy constructor.
Default Constructor
A default constructor is a type of constructor that requires no parameters when called. It is named
after the type it constructs and is a member function of it (as all constructors are).
class C{
int i;
public:
// the default constructor definition
C()
: i(0){ // member initializer list -- initialize i to 0
// constructor function body -- can do more complex things here
}
};
Another way to satisfy the "no parameters" requirement is for the developer to provide default
values for all parameters:
class D{
int i;
int j;
public:
// also a default constructor (can be called with no parameters)
D( int i = 0, int j = 42 )
: i(i), j(j){
}
};
D d; // calls constructor of D with the provided default values for the parameters
Under some circumstances (i.e., the developer provides no constructors and there are no other
disqualifying conditions), the compiler implicitly provides an empty default constructor:
class C{
std::string s; // note: members need to be default constructible themselves
};
https://riptutorial.com/ 582
Having some other type of constructor is one of the disqualifying conditions mentioned earlier:
class C{
int i;
public:
C( int i ) : i(i){}
};
c++11
To be sure a default constructor (functionally similar to the implicit one) is defined, a developer
could write an empty one explicitly.
c++11
In C++11, a developer can also use the delete keyword to prevent the compiler from providing a
default constructor.
class C{
int i;
public:
// default constructor is explicitly deleted
C() = delete;
};
Furthermore, a developer may also be explicit about wanting the compiler to provide a default
constructor.
class C{
int i;
public:
// does have automatically generated default constructor (same as implicit one)
C() = default;
C( int i ) : i(i){}
};
c++14
You can determine whether a type has a default constructor (or is a primitive type) using
std::is_default_constructible from <type_traits>:
https://riptutorial.com/ 583
class C1{ };
class C2{ public: C2(){} };
class C3{ public: C3(int){} };
c++11
Destructor
A destructor is a function without arguments that is called when a user-defined object is about to
be destroyed. It is named after the type it destructs with a ~ prefix.
class C{
int* is;
string s;
public:
C()
: is( new int[10] ){
}
void f(){
C c1; // calls default constructor
C c2[2]; // calls default constructor for both elements
C* c3 = new C[2]; // calls default constructor for both array elements
C_child c_ch; // when destructed calls destructor of s_ch and of C base (and in turn s)
Under most circumstances (i.e., a user provides no destructor, and there are no other disqualifying
conditions), the compiler provides a default destructor implicitly:
class C{
https://riptutorial.com/ 584
int i;
string s;
};
void f(){
C* c1 = new C;
delete c1; // C has a destructor
}
class C{
int m;
private:
~C(){} // not public destructor!
};
class C_container{
C c;
};
void f(){
C_container* c_cont = new C_container;
delete c_cont; // Compile ERROR: C has no accessible destructor
}
c++11
In C++11, a developer can override this behavior by preventing the compiler from providing a
default destructor.
class C{
int m;
public:
~C() = delete; // does NOT have implicit destructor
};
void f{
C c1;
} // Compile ERROR: C has no destructor
Furthermore, a developer may also be explicit about wanting the compiler to provide a default
destructor.
class C{
int m;
public:
~C() = default; // saying explicitly it does have implicit/empty destructor
};
void f(){
C c1;
} // C has a destructor -- c1 properly destroyed
c++11
https://riptutorial.com/ 585
You can determine whether a type has a destructor (or is a primitive type) using
std::is_destructible from <type_traits>:
class C1{ };
class C2{ public: ~C2() = delete };
class C3 : public C2{ };
https://riptutorial.com/ 586
Chapter 105: Standard Library Algorithms
Examples
std::for_each
Effects:
Applies f to the result of dereferencing every iterator in the range [first, last) starting from first
and proceeding to last - 1.
Parameters:
f - callable object which is applied to the result of dereferencing every iterator in the range [first,
last).
Return value:
Complexity:
Example:
c++11
std::vector<int> v { 1, 2, 4, 8, 16 };
std::for_each(v.begin(), v.end(), [](int elem) { std::cout << elem << " "; });
Applies the given function for every element of the vector v printing this element to stdout.
std::next_permutation
Effects:
Sift the data sequence of the range [first, last) into the next lexicographically higher permutation. If
cmpFun is provided, the permutation rule is customized.
https://riptutorial.com/ 587
Parameters:
first- the beginning of the range to be permutated, inclusive
last - the end of the range to be permutated, exclusive
Return Value:
Returns true if such permutation exists.
Otherwise the range is swaped to the lexicographically smallest permutation and return false.
Complexity:
O(n), n is the distance from first to last.
Example:
123
132
213
231
312
321
std::accumulate
Effects:
std::accumulate performs fold operation using f function on range [first, last) starting with init
as accumulator value.
T acc = init;
for (auto it = first; first != last; ++it)
https://riptutorial.com/ 588
acc = f(acc, *it);
return acc;
In version (1) operator+ is used in place of f, so accumulate over container is equivalent of sum of
container elements.
Parameters:
Return value:
Complexity:
O(n×k), where n is the distance from first to last, O(k) is complexity of f function.
Example:
std::vector<int> v { 2, 3, 4 };
auto sum = std::accumulate(v.begin(), v.end(), 1);
std::cout << sum << std::endl;
Output:
10
c++11
class Converter {
public:
int operator()(int a, int d) const { return a * 10 + d; }
};
and later
c++11
https://riptutorial.com/ 589
0,
[](int a, int d) { return a * 10 + d; });
std::cout << n << std::endl;
Output:
123
std::find
Effects
Finds the first occurrence of val within the range [first, last)
Parameters
first=> iterator pointing to the beginning of the range last => iterator pointing to the end of the
range val => The value to find within the range
Return
An iterator that points to the first element within the range that is equal(==) to val, the iterator
points to last if val is not found.
Example
#include <vector>
#include <algorithm>
#include <iostream>
//create a vector
vector<int> intVec {4, 6, 8, 9, 10, 30, 55,100, 45, 2, 4, 7, 9, 43, 48};
//define iterators
vector<int>::iterator itr_9;
vector<int>::iterator itr_43;
vector<int>::iterator itr_50;
//calling find
itr_9 = find(intVec.begin(), intVec.end(), 9); //occurs twice
itr_43 = find(intVec.begin(), intVec.end(), 43); //occurs once
cout << "first occurence of: " << *itr_9 << endl;
cout << "only occurence of: " << *itr_43 << Lendl;
https://riptutorial.com/ 590
/*
let's prove that itr_9 is pointing to the first occurence
of 9 by looking at the element after 9, which should be 10
not 43
*/
cout << "element after first 9: " << *(itr_9 + 1) << ends;
/*
to avoid dereferencing intVec.end(), lets look at the
element right before the end
*/
cout << "last element: " << *(itr_50 - 1) << endl;
return 0;
}
Output
std::count
Effects
Parameters
Return
Example
#include <vector>
#include <algorithm>
#include <iostream>
https://riptutorial.com/ 591
//create vector
vector<int> intVec{4,6,8,9,10,30,55,100,45,2,4,7,9,43,48};
//print result
cout << "There are " << count_9 << " 9s"<< endl;
cout << "There is " << count_55 << " 55"<< endl;
cout << "There is " << count_101 << " 101"<< ends;
//count its occurences in the vector starting from the first one
size_t count_4 = count(itr_4, intVec.end(), *itr_4); // should be 2
cout << "There are " << count_4 << " " << *itr_4 << endl;
return 0;
}
Output
There are 2 9s
There is 1 55
There is 0 101
There are 2 4
std::count_if
Effects
Counts the number of elements in a range for which a specified predicate function is true
Parameters
first=> iterator pointing to the beginning of the range last => iterator pointing to the end of the
range red => predicate function(returns true or false)
Return
The number of elements within the specified range for which the predicate function returned true.
Example
#include <iostream>
https://riptutorial.com/ 592
#include <vector>
#include <algorithm>
/*
Define a few functions to use as predicates
*/
//functor that returns true if number is greater than the value of the constructor parameter
provided
class Greater {
int _than;
public:
Greater(int th): _than(th){}
bool operator()(int i){
return i > _than;
}
};
//create a vector
vector<int> myvec = {1,5,8,0,7,6,4,5,2,1,5,0,6,9,7};
//using function pointer to count odd number in the first half of the vector
size_t oddCount = count_if(myvec.begin(), myvec.end()- myvec.size()/2, isOdd);
return 0;
}
Output
vector size: 15
even numbers: 7 found
odd numbers: 4 found
numbers > 5: 6 found
std::find_if
https://riptutorial.com/ 593
InputIterator find_if (InputIterator first, InputIterator last, UnaryPredicate pred);
Effects
Finds the first element in a range for which the predicate function pred returns true.
Parameters
first=> iterator pointing to the beginning of the range last => iterator pointing to the end of the
range pred => predicate function(returns true or false)
Return
An iterator that points to the first element within the range the predicate function pred returns true
for. The iterator points to last if val is not found
Example
#include <iostream>
#include <vector>
#include <algorithm>
/*
define some functions to use as predicates
*/
public:
Greater(int th):_than(th){
}
bool operator()(int data) const
{
return data > _than;
}
};
int main()
{
https://riptutorial.com/ 594
//with a function pointer
vector<int>::iterator pow10 = find_if(myvec.begin(), myvec.end(), multOf10);
//with functor
vector<int>::iterator gt5 = find_if(myvec.begin(), myvec.end(), Greater(5));
//not Found
vector<int>::iterator nf = find_if(myvec.begin(), myvec.end(), Greater(1000)); // nf points
to myvec.end()
cout << "First item > 10: " << *gt10 << endl;
cout << "First Item n * 10: " << *pow10 << endl;
cout << "First Item > 5: " << *gt5 << endl;
return 0;
}
Output
std::min_element
Effects
Parameters
https://riptutorial.com/ 595
Return
Complexity
Example
#include <iostream>
#include <algorithm>
#include <vector>
#include <utility> //to use make_pair
//Using pairLessThanFunction
auto minPairFunction = min_element(pairVector.begin(), pairVector.end(),
pairLessThanFunction);
return 0;
}
Output
The std::nth_element algorithm takes three iterators: an iterator to the beginning, nth position, and
https://riptutorial.com/ 596
end. Once the function returns, the nth element (by order) will be the nth smallest element. (The
function has more elaborate overloads, e.g., some taking comparison functors; see the above link
for all the variations.)
For the sake of this example, let's define the median of a sequence of length n as the element that
would be in position ⌈n / 2⌉. For example, the median of a sequence of length 5 is the 3rd smallest
element, and so is the median of a sequence of length 6.
To use this function to find the median, we can use the following. Say we start with
std::vector<int>::iterator b = v.begin();
std::vector<int>::iterator e = v.end();
std::vector<int>::iterator med = b;
std::advance(med, v.size() / 2);
To find the pth quantile, we would change some of the lines above:
std::advance(nth, pos);
https://riptutorial.com/ 597
Chapter 106: static_assert
Syntax
• static_assert( bool_constexpr, message )
• static_assert( bool_constexpr ) /* Since C++17 */
Parameters
Parameter Details
Remarks
Unlike runtime assertions, static assertions are checked at compile-time and are also enforced
when compiling optimized builds.
Examples
static_assert
Assertations mean that a condition should be checked and if it's false, it's an error. For
static_assert(), this is done compile-time.
template<typename T>
T mul10(const T t)
{
static_assert( std::is_integral<T>::value, "mul10() only works for integral types" );
return (t << 3) + (t << 1);
}
A static_assert() has a mandatory first parameter, the condition, that is a bool constexpr. It might
have a second parameter, the message, that is a string literal. From C++17, the second parameter
is optional; before that, it's mandatory.
C++17
template<typename T>
T mul10(const T t)
{
static_assert(std::is_integral<T>::value);
return (t << 3) + (t << 1);
}
https://riptutorial.com/ 598
It is used when:
Note that static_assert() does not participate in SFINAE: thus, when additional overloads /
specializations are possible, one should not use it instead of template metaprogramming
techniques (like std::enable_if<>). It might be used in template code when the expected overload /
specialization is already found, but further verifications are required. In such cases, it might
provide more concrete error message(s) than relying on SFINAE for this.
https://riptutorial.com/ 599
Chapter 107: std::any
Remarks
The class std::any provides a type-safe container to which we can put single values of any type.
Examples
Basic usage
try {
std::any_cast<int>(an_object);
} catch(std::bad_any_cast&) {
std::cout << "Wrong type\n";
}
std::any_cast<std::string&>(an_object) = "42";
std::cout << std::any_cast<std::string>(an_object) << '\n';
Output
hello world
Wrong type
42
https://riptutorial.com/ 600
Chapter 108: std::array
Parameters
Parameter Definition
Remarks
Use of a std::array requires the inclusion of the <array> header using #include <array>.
Examples
Initializing an std::array
Initializing std::array<T, N>, where T is a scalar type and N is the number of elements of type
T
// 1) Using aggregate-initialization
std::array<int, 3> a{ 0, 1, 2 };
// or equivalently
std::array<int, 3> a = { 0, 1, 2 };
Initializing std::array<T, N>, where T is a non-scalar type and N is the number of elements of
type T
https://riptutorial.com/ 601
// or equivalently
std::array<A, 2> a = { 0, 1, 2, 3, 4, 5 };
// 3)
std::array<A, 2> a{{ { 0, 1, 2 }, { 3, 4, 5 } }};
// or equivalently
std::array<A, 2> a = {{ { 0, 1, 2 }, { 3, 4, 5 } }};
Element access
1. at(pos)
Returns a reference to the element at position pos with bounds checking. If pos is not within the
range of the container, an exception of type std::out_of_range is thrown.
#include <array>
int main()
{
std::array<int, 3> arr;
// write values
arr.at(0) = 2;
arr.at(1) = 4;
arr.at(2) = 6;
// read values
int a = arr.at(0); // a is now 2
int b = arr.at(1); // b is now 4
int c = arr.at(2); // c is now 6
return 0;
}
2) operator[pos]
Returns a reference to the element at position pos without bounds checking. If pos is not within the
range of the container, a runtime segmentation violation error can occur. This method provides
element access equivalent to classic arrays and thereof more efficient than at(pos).
https://riptutorial.com/ 602
The complexity is constant O(1).
#include <array>
int main()
{
std::array<int, 3> arr;
// write values
arr[0] = 2;
arr[1] = 4;
arr[2] = 6;
// read values
int a = arr[0]; // a is now 2
int b = arr[1]; // b is now 4
int c = arr[2]; // c is now 6
return 0;
}
3) std::get<pos>
This non-member function returns a reference to the element at compile-time constant position
pos without bounds checking. If pos is not within the range of the container, a runtime segmentation
violation error can occur.
#include <array>
int main()
{
std::array<int, 3> arr;
// write values
std::get<0>(arr) = 2;
std::get<1>(arr) = 4;
std::get<2>(arr) = 6;
// read values
int a = std::get<0>(arr); // a is now 2
int b = std::get<1>(arr); // b is now 4
int c = std::get<2>(arr); // c is now 6
return 0;
}
4) front()
Returns a reference to the first element in container. Calling front() on an empty container is
undefined.
https://riptutorial.com/ 603
#include <array>
int main()
{
std::array<int, 3> arr{ 2, 4, 6 };
return 0;
}
5) back()
Returns reference to the last element in the container. Calling back() on an empty container is
undefined.
#include <array>
int main()
{
std::array<int, 3> arr{ 2, 4, 6 };
return 0;
}
6) data()
Returns pointer to the underlying array serving as element storage. The pointer is such that range
[data(); data() + size()) is always a valid range, even if the container is empty (data() is not
dereferenceable in that case).
#include <iostream>
#include <cstring>
#include <array>
int main ()
{
const char* cstr = "Test string";
std::array<char, 12> arr;
return 0;
}
https://riptutorial.com/ 604
One of the main advantage of std::array as compared to C style array is that we can check the
size of the array using size() member function
int main() {
std::array<int, 3> arr = { 1, 2, 3 };
cout << arr.size() << endl;
}
std::array being a STL container, can use range-based for loop similar to other containers like
vector
int main() {
std::array<int, 3> arr = { 1, 2, 3 };
for (auto i : arr)
cout << i << '\n';
}
The member function fill() can be used on std::array for changing the values at once post
initialization
int main() {
https://riptutorial.com/ 605
Chapter 109: std::atomics
Examples
atomic types
Each instantiation and full specialization of the std::atomic template defines an atomic type. If one
thread writes to an atomic object while another thread reads from it, the behavior is well-defined
(see memory model for details on data races)
In addition, accesses to atomic objects may establish inter-thread synchronization and order non-
atomic memory accesses as specified by std::memory_order.
std::atomic may be instantiated with any TriviallyCopyable type T. std::atomic is neither copyable
nor movable.
The standard library provides specializations of the std::atomic template for the following types:
1. One full specialization for the type bool and its typedef name is defined that is treated as a
non-specialized std::atomic<T> except that it has standard layout, trivial default constructor,
trivial destructors, and supports aggregate initialization syntax:
std::atomic_bool std::atomic<bool>
std::atomic_char std::atomic<char>
std::atomic_char std::atomic<char>
std::atomic_short std::atomic<short>
std::atomic_int std::atomic<int>
std::atomic_long std::atomic<long>
https://riptutorial.com/ 606
Typedef name Full specialization
std::atomic_char16_t std::atomic<char16_t>
std::atomic_char32_t std::atomic<char32_t>
std::atomic_wchar_t std::atomic<wchar_t>
std::atomic_int8_t std::atomic<std::int8_t>
std::atomic_uint8_t std::atomic<std::uint8_t>
std::atomic_int16_t std::atomic<std::int16_t>
std::atomic_uint16_t std::atomic<std::uint16_t>
std::atomic_int32_t std::atomic<std::int32_t>
std::atomic_uint32_t std::atomic<std::uint32_t>
std::atomic_int64_t std::atomic<std::int64_t>
std::atomic_uint64_t std::atomic<std::uint64_t>
std::atomic_int_least8_t std::atomic<std::int_least8_t>
std::atomic_uint_least8_t std::atomic<std::uint_least8_t>
std::atomic_int_least16_t std::atomic<std::int_least16_t>
std::atomic_uint_least16_t std::atomic<std::uint_least16_t>
std::atomic_int_least32_t std::atomic<std::int_least32_t>
std::atomic_uint_least32_t std::atomic<std::uint_least32_t>
std::atomic_int_least64_t std::atomic<std::int_least64_t>
std::atomic_uint_least64_t std::atomic<std::uint_least64_t>
std::atomic_int_fast8_t std::atomic<std::int_fast8_t>
std::atomic_uint_fast8_t std::atomic<std::uint_fast8_t>
std::atomic_int_fast16_t std::atomic<std::int_fast16_t>
std::atomic_uint_fast16_t std::atomic<std::uint_fast16_t>
std::atomic_int_fast32_t std::atomic<std::int_fast32_t>
std::atomic_uint_fast32_t std::atomic<std::uint_fast32_t>
std::atomic_int_fast64_t std::atomic<std::int_fast64_t>
std::atomic_uint_fast64_t std::atomic<std::uint_fast64_t>
std::atomic_intptr_t std::atomic<std::intptr_t>
std::atomic_uintptr_t std::atomic<std::uintptr_t>
std::atomic_size_t std::atomic<std::size_t>
https://riptutorial.com/ 607
Typedef name Full specialization
std::atomic_ptrdiff_t std::atomic<std::ptrdiff_t>
std::atomic_intmax_t std::atomic<std::intmax_t>
std::atomic_uintmax_t std::atomic<std::uintmax_t>
void set_foo(int x) {
foo.store(x,std::memory_order_relaxed); // set value atomically
}
void print_foo() {
int x;
do {
x = foo.load(std::memory_order_relaxed); // get value atomically
} while (x==0);
std::cout << "foo: " << x << '\n';
}
int main ()
{
std::thread first (print_foo);
std::thread second (set_foo,10);
first.join();
//second.join();
return 0;
}
//output: foo: 10
https://riptutorial.com/ 608
Chapter 110: std::forward_list
Introduction
std::forward_list is a container that supports fast insertion and removal of elements from
anywhere in the container. Fast random access is not supported. It is implemented as a singly-
linked list and essentially does not have any overhead compared to its implementation in C.
Compared to std::list this container provides more space efficient storage when bidirectional
iteration is not needed.
Remarks
Adding, removing and moving the elements within the list, or across several lists, does not
invalidate the iterators currently referring to other elements in the list. However, an iterator or
reference referring to an element is invalidated when the corresponding element is removed (via
erase_after) from the list. std::forward_list meets the requirements of Container (except for the
size member function and that operator=='s complexity is always linear), AllocatorAwareContainer
and SequenceContainer.
Examples
Example
#include <forward_list>
#include <string>
#include <iostream>
template<typename T>
std::ostream& operator<<(std::ostream& s, const std::forward_list<T>& v) {
s.put('[');
char comma[3] = {'\0', ' ', '\0'};
for (const auto& e : v) {
s << comma << e;
comma[0] = ',';
}
return s << ']';
}
int main()
{
// c++11 initializer list syntax:
std::forward_list<std::string> words1 {"the", "frogurt", "is", "also", "cursed"};
std::cout << "words1: " << words1 << '\n';
// words2 == words1
std::forward_list<std::string> words2(words1.begin(), words1.end());
std::cout << "words2: " << words2 << '\n';
// words3 == words1
std::forward_list<std::string> words3(words1);
https://riptutorial.com/ 609
std::cout << "words3: " << words3 << '\n';
Output:
Methods
------ ------
Element access
------ ------
Iterators
Capacity
https://riptutorial.com/ 610
Method name Definition
Modifiers
Operations
https://riptutorial.com/ 611
Chapter 111: std::function: To wrap any
element that is callable
Examples
Simple usage
#include <iostream>
#include <functional>
std::function<void(int , const std::string&)> myFuncObj;
void theFunc(int i, const std::string& s)
{
std::cout << s << ": " << i << std::endl;
}
int main(int argc, char *argv[])
{
myFuncObj = theFunc;
myFuncObj(10, "hello world");
}
Think about a situation where we need to callback a function with arguments. std::function used
with std::bind gives a very powerful design construct as shown below.
class A
{
public:
std::function<void(int, const std::string&)> m_CbFunc = nullptr;
void foo()
{
if (m_CbFunc)
{
m_CbFunc(100, "event fired");
}
}
};
class B
{
public:
B()
{
auto aFunc = std::bind(&B::eventHandler, this, std::placeholders::_1,
std::placeholders::_2);
anObjA.m_CbFunc = aFunc;
}
void eventHandler(int i, const std::string& s)
{
std::cout << s << ": " << i << std::endl;
}
https://riptutorial.com/ 612
void DoSomethingOnA()
{
anObjA.foo();
}
A anObjA;
};
#include <iostream>
#include <functional>
int main()
{
int a = 2;
/* Function pointers */
std::cout << stdf_foobar(a, &foo) << std::endl; // 6 ( 2 + (2+2) )
// can also be: stdf_foobar(2, foo)
/* Lambda expressions */
/* An unnamed closure from a lambda expression can be
* stored in a std::function object:
*/
int capture_value = 3;
std::cout << stdf_foobar(a,
[capture_value](int param) -> int { return 7 + capture_value *
param; })
<< std::endl;
// result: 15 == value + (7 * capture_value * value) == 2 + (7 + 3 * 2)
/* std::bind expressions */
/* The result of a std::bind expression can be passed.
* For example by binding parameters to a function pointer call:
*/
int b = stdf_foobar(a, std::bind(foo_2, _1, 3));
std::cout << b << std::endl;
// b == 23 == 2 + ( 9*2 + 3 )
int c = stdf_foobar(a, std::bind(foo_2, 5, _1));
std::cout << c << std::endl;
https://riptutorial.com/ 613
// c == 49 == 2 + ( 9*5 + 2 )
return 0;
}
`function` overhead
std::function can cause significant overhead. Because std::function has [value semantics][1], it
must copy or move the given callable into itself. But since it can take callables of an arbitrary type,
it will frequently have to allocate memory dynamically to do this.
Some function implementations have so-called "small object optimization", where small types (like
function pointers, member pointers, or functors with very little state) will be stored directly in the
function object. But even this only works if the type is noexcept move constructible. Furthermore,
the C++ standard does not require that all implementations provide one.
//Header file
using MyPredicate = std::function<bool(const MyValue &, const MyValue &)>;
//Source file
void SortMyContainer(MyContainer &C, const MyPredicate &pred)
{
std::sort(C.begin(), C.end(), pred);
}
A template parameter would be the preferred solution for SortMyContainer, but let us assume that
this is not possible or desirable for whatever reason. SortMyContainer does not need to store pred
beyond its own call. And yet, pred may well allocate memory if the functor given to it is of some
non-trivial size.
function allocates memory because it needs something to copy/move into; function takes
ownership of the callable it is given. But SortMyContainer does not need to own the callable; it's just
referencing it. So using function here is overkill; it may be efficient, but it may not.
There is no standard library function type that merely references a callable. So an alternate
solution will have to be found, or you can choose to live with the overhead.
Also, function has no effective means to control where the memory allocations for the object come
from. Yes, it has constructors that take an allocator, but [many implementations do not implement
them correctly... or even at all][2].
C++17
The function constructors that take an allocator no longer are part of the type. Therefore, there is
no way to manage the allocation.
Calling a function is also slower than calling the contents directly. Since any function instance
https://riptutorial.com/ 614
could hold any callable, the call through a function must be indirect. The overhead of calling
function is on the order of a virtual function call.
/*
* This example show some ways of using std::function to call
* a) C-like function
* b) class-member function
* c) operator()
* d) lambda function
*
* Function call can be made:
* a) with right arguments
* b) argumens with different order, types and count
*/
#include <iostream>
#include <functional>
#include <iostream>
#include <vector>
using std::cout;
using std::endl;
using namespace std::placeholders;
https://riptutorial.com/ 615
<< std::endl;
return res;
}
// overloaded operator() makes whole object to be callable
double operator()(int x, float y, double z)
{
double res = x + y + z;
std::cout << "foo_struct::operator() called with arguments: "
<< x << ", " << y << ", " << z
<< " result is : " << res
<< std::endl;
return res;
}
};
int main(void)
{
// typedefs
using function_type = std::function<double(int, float, double)>;
// foo_struct instance
foo_struct fs;
https://riptutorial.com/ 616
}
Live
Output:
Some programs need so store arguments for future calling of some function.
This example shows how to call any function with arguments stored in std::tuple
#include <iostream>
#include <functional>
#include <tuple>
#include <iostream>
// invocation helper
template<typename FN, typename P, int ...S>
double call_fn_internal(const FN& fn, const P& params, const seq<S...>)
{
return fn(std::get<S>(params) ...);
}
// call function with arguments stored in std::tuple
template<typename Ret, typename ...Args>
Ret call_fn(const std::function<Ret(Args...)>& fn,
const std::tuple<Args...>& params)
{
return call_fn_internal(fn, params, typename gens<sizeof...(Args)>::type());
}
int main(void)
{
// arguments
https://riptutorial.com/ 617
std::tuple<int, float, double> t = std::make_tuple(1, 5, 10);
// function to call
std::function<double(int, float, double)> fn = foo_fn;
Live
Output:
https://riptutorial.com/ 618
Chapter 112: std::integer_sequence
Introduction
The class template std::integer_sequence<Type, Values...> represents a sequence of values of
type Type where Type is one of the built-in integer types. These sequences are used when
implementing class or function templates which benefit from positional access. The standard
library also contains "factory" types which create ascending sequences of integer values just from
the number of elements.
Examples
Turn a std::tuple into function parameters
A std::tuple<T...> can be used to pass multiple values around. For example, it could be used to
store a sequence of parameters into some form of a queue. When processing such a tuple its
elements need to be turned into function call arguments:
#include <array>
#include <iostream>
#include <string>
#include <tuple>
#include <utility>
// ----------------------------------------------------------------------------
// Example functions to be called:
void f(int i, std::string const& s) {
std::cout << "f(" << i << ", " << s << ")\n";
}
void f(int i, double d, std::string const& s) {
std::cout << "f(" << i << ", " << d << ", " << s << ")\n";
}
void f(char c, int i, double d, std::string const& s) {
std::cout << "f(" << c << ", " << i << ", " << d << ", " << s << ")\n";
}
void f(int i, int j, int k) {
std::cout << "f(" << i << ", " << j << ", " << k << ")\n";
}
// ----------------------------------------------------------------------------
// The actual function expanding the tuple:
template <typename Tuple, std::size_t... I>
void process(Tuple const& tuple, std::index_sequence<I...>) {
f(std::get<I>(tuple)...);
}
https://riptutorial.com/ 619
// ----------------------------------------------------------------------------
int main() {
process(std::make_tuple(1, 3.14, std::string("foo")));
process(std::make_tuple('a', 2, 2.71, std::string("bar")));
process(std::make_pair(3, std::string("pair")));
process(std::array<int, 3>{ 1, 2, 3 });
}
std::integer_sequence itself is about holding a sequence of integers which can be turned into a
parameter pack. Its primary value is the possibility to create "factory" class templates creating
these sequences:
#include <iostream>
#include <initializer_list>
#include <utility>
int main() {
// explicitly specify sequences:
print_sequence(std::integer_sequence<int, 1, 2, 3>());
print_sequence(std::integer_sequence<char, 'f', 'o', 'o'>());
// generate sequences:
print_sequence(std::make_index_sequence<10>());
print_sequence(std::make_integer_sequence<short, 10>());
print_offset_sequence<'A'>(std::make_integer_sequence<char, 26>());
}
Expanding the parameter pack of indices in a comma expression with a value creates a copy of
the value for each of the indices. Sadly, gcc and clang think the index has no effect and warn about
it (gcc can be silenced by casting the index to void):
https://riptutorial.com/ 620
#include <algorithm>
#include <array>
#include <iostream>
#include <iterator>
#include <string>
#include <utility>
int main() {
auto array = make_array<20>(std::string("value"));
std::copy(array.begin(), array.end(),
std::ostream_iterator<std::string>(std::cout, " "));
std::cout << "\n";
}
https://riptutorial.com/ 621
Chapter 113: std::iomanip
Examples
std::setw
This outputs:
10
10
1234567890
(where the last line is there to aid in seeing the character offsets).
Sometimes we need to set the width of the output field, usually when we need to get the output in
some structured and proper layout. That can be done using std::setw of std::iomanip.
std::setw(int n)
std::setprecision
When used in an expression out << setprecision(n) or in >> setprecision(n), sets the precision
parameter of the stream out or in to exactly n. Parameter of this function is integer, which is new
value for precision.
Example:
#include <iostream>
#include <iomanip>
#include <cmath>
#include <limits>
int main()
{
const long double pi = std::acos(-1.L);
std::cout << "default precision (6): " << pi << '\n'
<< "std::precision(10): " << std::setprecision(10) << pi << '\n'
<< "max precision: "
<< std::setprecision(std::numeric_limits<long double>::digits10 + 1)
<< pi << '\n';
https://riptutorial.com/ 622
}
//Output
//default precision (6): 3.14159
//std::precision(10): 3.141592654
//max precision: 3.141592653589793239
std::setfill
When used in an expression out << setfill(c) sets the fill character of the stream out to c.
Example:
#include <iostream>
#include <iomanip>
int main()
{
std::cout << "default fill: " << std::setw(10) << 42 << '\n'
<< "setfill('*'): " << std::setfill('*')
<< std::setw(10) << 42 << '\n';
}
//output::
//default fill: 42
//setfill('*'): ********42
std::setiosflags
When used in an expression out << setiosflags(mask) or in >> setiosflags(mask), sets all format
flags of the stream out or in as specified by the mask.
https://riptutorial.com/ 623
output
• showpos - generate a + character for non-negative numeric output
• skipws - skip leading whitespace before certain input operations
• unitbuf flush the output after each output operation
• uppercase - replace certain lowercase letters with their uppercase equivalents in certain
output output operations
Example of manipulators:
#include <iostream>
#include <string>
#include<iomanip>
int main()
{
int l_iTemp = 47;
std::cout<< std::resetiosflags(std::ios_base::basefield);
std::cout<<std::setiosflags( std::ios_base::oct)<<l_iTemp<<std::endl;
//output: 57
std::cout<< std::resetiosflags(std::ios_base::basefield);
std::cout<<std::setiosflags( std::ios_base::hex)<<l_iTemp<<std::endl;
//output: 2f
std::cout<<std::setiosflags( std::ios_base::uppercase)<<l_iTemp<<std::endl;
//output 2F
std::cout<<std::setfill('0')<<std::setw(12);
std::cout<<std::resetiosflags(std::ios_base::uppercase);
std::cout<<std::setiosflags( std::ios_base::right)<<l_iTemp<<std::endl;
//output: 00000000002f
std::cout<<std::resetiosflags(std::ios_base::basefield|std::ios_base::adjustfield);
std::cout<<std::setfill('.')<<std::setw(10);
std::cout<<std::setiosflags( std::ios_base::left)<<l_iTemp<<std::endl;
//output: 47........
std::cout<<std::resetiosflags(std::ios_base::adjustfield)<<std::setfill('#');
std::cout<<std::setiosflags(std::ios_base::internal|std::ios_base::showpos);
std::cout<<std::setw(10)<<l_iTemp<<std::endl;
//output +#######47
https://riptutorial.com/ 624
Chapter 114: std::map
Remarks
• To use any of std::map or std::multimap the header file <map> should be included.
• std::map and std::multimap both keep their elements sorted according to the ascending order
of keys. In case of std::multimap, no sorting occurs for the values of the same key.
• The basic difference between std::map and std::multimap is that the std::map one does not
allow duplicate values for the same key where std::multimap does.
• Maps are implemented as binary search trees. So search(), insert(), erase() takes Θ(log n)
time in average. For constant time operation use std::unordered_map.
• size()and empty() functions have Θ(1) time complexity, number of nodes is cached to avoid
walking through tree each time these functions are called.
Examples
Accessing elements
ranking["stackoverflow"]=2;
ranking["docs-beta"]=1;
In the above example, if the key stackoverflow is already present, its value will be updated to 2. If it
isn't already present, a new entry will be created.
Note that using the operator[] on the map will actually insert a new value with the queried key into
the map. This means that you cannot use it on a const std::map, even if the key is already stored
in the map. To prevent this insertion, check if the element exists (for example by using find()) or
use at() as described below.
C++11
https://riptutorial.com/ 625
Elements of a std::map can be accessed with at():
Note that at() will throw an std::out_of_range exception if the container does not contain the
requested element.
In both containers std::map and std::multimap, elements can be accessed using iterators:
C++11
std::map and std::multimap both can be initialized by providing key-value pairs separated by
comma. Key-value pairs could be provided by either {key, value} or can be explicitly created by
std::make_pair(key, value). As std::map does not allow duplicate keys and comma operator
performs right to left, the pair on right would be overwritten with the pair with same key on the left.
https://riptutorial.com/ 626
std::multimap< int , int > mmp{ {1, 2}, {3, 4}, {6, 5}, {8, 9}, {6, 8}, {3, 4},
{6, 7} };
// {1, 2}, {3, 4}, {3, 4}, {6, 5}, {6, 8}, {6, 7}, {8, 9}
auto it = mmp.begin();
std::advance(it,3); //moved cursor on first {6, 5}
std::map< int, int > mp(it, mmp.end()); // {6, 5}, {8, 9}
Deleting elements
std::multimap< int , int > mmp{ {1, 2}, {3, 4}, {6, 5}, {8, 9}, {3, 4}, {6, 7} };
mmp.clear(); //empty multimap
std::multimap< int , int > mmp{ {1, 2}, {3, 4}, {6, 5}, {8, 9}, {3, 4}, {6, 7} };
// {1, 2}, {3, 4}, {3, 4}, {6, 5}, {6, 7}, {8, 9}
auto it = mmp.begin();
std::advance(it,3); // moved cursor on first {6, 5}
mmp.erase(it); // {1, 2}, {3, 4}, {3, 4}, {6, 7}, {8, 9}
std::multimap< int , int > mmp{ {1, 2}, {3, 4}, {6, 5}, {8, 9}, {3, 4}, {6, 7} };
// {1, 2}, {3, 4}, {3, 4}, {6, 5}, {6, 7}, {8, 9}
auto it = mmp.begin();
auto it2 = it;
it++; //moved first cursor on first {3, 4}
std::advance(it2,3); //moved second cursor on first {6, 5}
mmp.erase(it,it2); // {1, 2}, {6, 5}, {6, 7}, {8, 9}
std::multimap< int , int > mmp{ {1, 2}, {3, 4}, {6, 5}, {8, 9}, {3, 4}, {6, 7} };
// {1, 2}, {3, 4}, {3, 4}, {6, 5}, {6, 7}, {8, 9}
mmp.erase(6); // {1, 2}, {3, 4}, {3, 4}, {8, 9}
std::map<int,int> m;
https://riptutorial.com/ 627
auto it = m.begin();
while (it != m.end())
{
if (pred(*it))
it = m.erase(it);
else
++it;
}
Inserting elements
An element can be inserted into a std::map only if its key is not already present in the map. Given
for example:
• A key-value pair is inserted into a std::map through the insert() member function. It requires
a pair as an argument:
fruits_count.insert({"grapes", 20});
fruits_count.insert(make_pair("orange", 30));
fruits_count.insert(pair<std::string, size_t>("banana", 40));
fruits_count.insert(map<std::string, size_t>::value_type("cherry", 50));
The insert() function returns a pair consisting of an iterator and a bool value:
○ If the insertion was successful, the iterator points to the newly inserted element, and
the bool value is true.
○ If there was already an element with the same key, the insertion fails. When that
happens, the iterator points to the element causing the conflict, and the bool is value is
false.
The following method can be used to combine insertion and searching operation:
• For convenience, the std::map container provides the subscript operator to access elements
in the map and to insert new ones if they don't exist:
fruits_count["apple"] = 10;
While simpler, it prevents the user from checking if the element already exists. If an element
is missing, std::map::operator[] implicitly creates it, initializing it with the default constructor
before overwriting it with the supplied value.
• insert() can be used to add several elements at once using a braced list of pairs. This
version of insert() returns void:
https://riptutorial.com/ 628
fruits_count.insert({{"apricot", 1}, {"jackfruit", 1}, {"lime", 1}, {"mango", 7}});
• insert() can also be used to add elements by using iterators denoting the begin and end of
value_type values:
std::map< std::string, size_t > fruit_list{ {"lemon", 0}, {"olive", 0}, {"plum", 0}};
fruits_count.insert(fruit_list.begin(), fruit_list.end());
Example:
Time complexity for an insertion operation is O(log n) because std::map are implemented as trees.
C++11
If we know where the new element will be inserted, then we can use emplace_hint() to specify an
iterator hint. If the new element can be inserted just before hint, then the insertion can be done in
constant time. Otherwise it behaves in the same way as emplace():
std::multimap< int , int > mmp{ {1, 2}, {3, 4}, {6, 5}, {8, 9}, {3, 4}, {6, 7} };
//Forward iterator for loop: it would loop through first element to last element
//it will be a std::map< int, int >::iterator
https://riptutorial.com/ 629
for (auto it = mmp.begin(); it != mmp.end(); ++it)
std::cout<< it->first <<":"<< it->second << std::endl; //Do something with iterator
//Backward iterator for loop: it would loop through last element to first element
//it will be a std::map< int, int >::reverse_iterator
for (auto it = mmp.rbegin(); it != mmp.rend(); ++it)
std::cout<< it->first <<" "<< it->second << std::endl; //Do something with iterator
While iterating over a std::map or a std::multimap, the use of auto is preferred to avoid useless
implicit conversions (see this SO answer for more details).
• To get the iterator of the first occurrence of a key, the find() function can be used. It returns
end() if the key does not exist.
std::multimap< int , int > mmp{ {1, 2}, {3, 4}, {6, 5}, {8, 9}, {3, 4}, {6, 7} };
auto it = mmp.find(6);
if(it!=mmp.end())
std::cout << it->first << ", " << it->second << std::endl; //prints: 6, 5
else
std::cout << "Value does not exist!" << std::endl;
it = mmp.find(66);
if(it!=mmp.end())
std::cout << it->first << ", " << it->second << std::endl;
else
std::cout << "Value does not exist!" << std::endl; // This line would be executed.
• Another way to find whether an entry exists in std::map or in std::multimap is using the
count() function, which counts how many values are associated with a given key. Since
std::map associates only one value with each key, its count() function can only return 0 (if the
key is not present) or 1 (if it is). For std::multimap, count() can return values greater than 1
since there can be several values associated with the same key.
std::map< int , int > mp{ {1, 2}, {3, 4}, {6, 5}, {8, 9}, {3, 4}, {6, 7} };
if(mp.count(3) > 0) // 3 exists as a key in map
std::cout << "The key exists!" << std::endl; // This line would be executed.
else
std::cout << "The key does not exist!" << std::endl;
If you only care whether some element exists, find is strictly better: it documents your intent
and, for multimaps, it can stop once the first matching element has been found.
• In the case of std::multimap, there could be several elements having the same key. To get
this range, the equal_range() function is used which returns std::pair having iterator lower
bound (inclusive) and upper bound (exclusive) respectively. If the key does not exist, both
iterators would point to end().
https://riptutorial.com/ 630
auto st = eqr.first, en = eqr.second;
for(auto it = st; it != en; ++it){
std::cout << it->first << ", " << it->second << std::endl;
}
// prints: 6, 5
// 6, 7
The container std::map has a member function empty(), which returns true or false, depending on
whether the map is empty or not. The member function size() returns the number of element
stored in a std::map container:
Types of Maps
Regular Map
A map is an associative container, containing key-value pairs.
#include <string>
#include <map>
std::map<std::string, size_t> fruits_count;
In the above example, std::string is the key type, and size_t is a value.
The key acts as an index in the map. Each key must be unique, and must be ordered.
• If you need mutliple elements with the same key, consider using multimap (explained below)
• If your value type does not specify any ordering, or you want to override the default ordering,
you may provide one:
#include <string>
#include <map>
#include <cstring>
struct StrLess {
bool operator()(const std::string& a, const std::string& b) {
return strncmp(a.c_str(), b.c_str(), 8)<0;
//compare only up to 8 first characters
}
}
std::map<std::string, size_t, StrLess> fruits_count2;
https://riptutorial.com/ 631
If StrLess comparator returns false for two keys, they are considered the same even if their
actual contents differ.
Multi-Map
Multimap allows multiple key-value pairs with the same key to be stored in the map. Otherwise, its
interface and creation is very similar to the regular map.
#include <string>
#include <map>
std::multimap<std::string, size_t> fruits_count;
std::multimap<std::string, size_t, StrLess> fruits_count2;
#include <string>
#include <unordered_map>
std::unordered_map<std::string, size_t> fruits_count;
Unordered maps are usually faster, but the elements are not stored in any predictable order. For
example, iterating over all elements in an unordered_map gives the elements in a seemingly random
order.
In order to be able to use a class as the key in a map, all that is required of the key is that it be
copiable and assignable. The ordering within the map is defined by the third argument to the
template (and the argument to the constructor, if used). This defaults to std::less<KeyType>, which
defaults to the < operator, but there's no requirement to use the defaults. Just write a comparison
operator (preferably as a functional object):
struct CmpMyType
{
bool operator()( MyType const& lhs, MyType const& rhs ) const
{
// ...
}
};
In C++, the "compare" predicate must be a strict weak ordering. In particular, compare(X,X) must
return false for any X. i.e. if CmpMyType()(a, b) returns true, then CmpMyType()(b, a) must return
false, and if both return false, the elements are considered equal (members of the same
equivalence class).
https://riptutorial.com/ 632
Strict Weak Ordering
This is a mathematical term to define a relationship between two objects.
Its definition is:
Two objects x and y are equivalent if both f(x, y) and f(y, x) are false. Note that an
object is always (by the irreflexivity invariant) equivalent to itself.
In terms of C++ this means if you have two objects of a given type, you should return the following
values when compared with the operator <.
X a;
X b;
How you define equivalent/less is totally dependent on the type of your object.
https://riptutorial.com/ 633
Chapter 115: std::optional
Examples
Introduction
Optionals (also known as Maybe types) are used to represent a type whose contents may or may
not be present. They are implemented in C++17 as the std::optional class. For example, an
object of type std::optional<int> may contain some value of type int, or it may contain no value.
Optionals are commonly used either to represent a value that may not exist or as a return type
from a function that can fail to return a meaningful result.
Optional vs Pointer
In some cases, we can provide a pointer to an existing object or nullptr to indicate failure. But this
is limited to those cases where objects already exist - optional, as a value type, can also be used
to return new objects without resorting to memory allocation.
Optional vs Sentinel
A common idiom is to use a special value to indicate that the value is meaningless. This may be 0
or -1 for integral types, or nullptr for pointers. However, this reduces the space of valid values
(you cannot differentiate between a valid 0 and a meaningless 0) and many types do not have a
natural choice for the sentinel value.
Another common idiom is to provide a pair, where one of the elements is a bool indicating whether
or not the value is meaningful.
This relies upon the value type being default-constructible in the case of error, which is not
possible for some types and possible but undesirable for others. An optional<T>, in the case of
error, does not need to construct anything.
Before C++17, having pointers with a value of nullptr commonly represented the absence of a
value. This is a good solution for large objects that have been dynamically allocated and are
already managed by pointers. However, this solution does not work well for small or primitive
https://riptutorial.com/ 634
types such as int, which are rarely ever dynamically allocated or managed by pointers.
std::optional provides a viable solution to this common problem.
In this example, struct Person is defined. It is possible for a person to have a pet, but not
necessary. Therefore, the pet member of Person is declared with an std::optional wrapper.
#include <iostream>
#include <optional>
#include <string>
struct Animal {
std::string name;
};
struct Person {
std::string name;
std::optional<Animal> pet;
};
int main() {
Person person;
person.name = "John";
if (person.pet) {
std::cout << person.name << "'s pet's name is " <<
person.pet->name << std::endl;
}
else {
std::cout << person.name << " is alone." << std::endl;
}
}
In this example, John is given two pets, Fluffy and Furball. The function Person::pet_with_name() is
then called to retrieve John's pet Whiskers. Since John does not have a pet named Whiskers, the
function fails and std::nullopt is returned instead.
https://riptutorial.com/ 635
#include <iostream>
#include <optional>
#include <string>
#include <vector>
struct Animal {
std::string name;
};
struct Person {
std::string name;
std::vector<Animal> pets;
int main() {
Person john;
john.name = "John";
Animal fluffy;
fluffy.name = "Fluffy";
john.pets.push_back(fluffy);
Animal furball;
furball.name = "Furball";
john.pets.push_back(furball);
Here we return either the fraction a/b, but if it is not defined (would be infinity) we instead return
the empty optional.
https://riptutorial.com/ 636
auto find_if( Range&& r, Pred&& p ) {
using std::begin; using std::end;
auto b = begin(r), e = end(r);
auto r = std::find_if(b, e , p );
using iterator = decltype(r);
if (r==e)
return std::optional<iterator>();
return std::optional<iterator>(r);
}
template<class Range, class T>
auto find( Range&& r, T const& t ) {
return find_if( std::forward<Range>(r), [&t](auto&& x){return x==t;} );
}
find( some_range, 7 )searches the container or range some_range for something equal to the
number 7. find_if does it with a predicate.
It returns either an empty optional if it was not found, or an optional containing an iterator tothe
element if it was.
if (find( vec, 7 )) {
// code
}
or even
value_or
value_or either returns the value stored in the optional, or the argument if there is nothing store
there.
This lets you take the maybe-null optional and give a default behavior when you actually need a
value. By doing it this way, the "default behavior" decision can be pushed back to the point where
it is best made and immediately needed, instead of generating some default value deep in the guts
of some engine.
https://riptutorial.com/ 637
Chapter 116: std::pair
Examples
Creating a Pair and accessing the elements
Pair allows us to treat two objects as one object. Pairs can be easily constructed with the help of
template function std::make_pair.
Alternative way is to create pair and assign its elements (first and second) later.
#include <iostream>
#include <utility>
int main()
{
std::pair<int,int> p = std::make_pair(1,2); //Creating the pair
std::cout << p.first << " " << p.second << std::endl; //Accessing the elements
//We can also create a pair and assign the elements later
std::pair<int,int> p1;
p1.first = 3;
p1.second = 4;
std::cout << p1.first << " " << p1.second << std::endl;
return 0;
}
Compare operators
• operator== tests if both elements on lhs and rhs pair are equal. The return value is true if
both lhs.first == rhs.first AND lhs.second == rhs.second, otherwise false
if (p1 == p2)
std::cout << "equals";
else
std::cout << "not equal"//statement will show this, because they are not identical
• operator!= tests if any elements on lhs and rhs pair are not equal. The return value is true if
either lhs.first != rhs.first OR lhs.second != rhs.second, otherwise return false.
https://riptutorial.com/ 638
• operator< tests if lhs.first<rhs.first, returns true. Otherwise, if rhs.first<lhs.first returns
false. Otherwise, if lhs.second<rhs.second returns true, otherwise, returns false.
Another example with containers of pairs. It uses operator< because it needs to sort
container.
#include <iostream>
#include <utility>
#include <vector>
#include <algorithm>
#include <string>
int main()
{
std::vector<std::pair<int, std::string>> v = { {2, "baz"},
{2, "bar"},
{1, "foo"} };
std::sort(v.begin(), v.end());
for(const auto& p: v) {
std::cout << "(" << p.first << "," << p.second << ") ";
//output: (1,foo) (2,bar) (2,baz)
}
}
https://riptutorial.com/ 639
Chapter 117: std::set and std::multiset
Introduction
setis a type of container whose elements are sorted and unique. multiset is similar, but, in the
case of multiset, multiple elements can have the same value.
Remarks
Different styles of C++ have been used in those examples. Be careful that if you are using a
C++98 compiler; some of this code may not be usable.
Examples
Inserting values in a set
• First, a simple insert of the value. This method returns a pair allowing the caller to check
whether the insert really occurred.
• Second, an insert by giving a hint of where the value will be inserted. The objective is to
optimize the insertion time in such a case, but knowing where a value should be inserted is
not the common case. Be careful in that case; the way to give a hint differs with
compiler versions.
• Finally you can insert a range of values by giving a starting and an ending pointer. The
starting one will be included in the insertion, the ending one is excluded.
#include <iostream>
#include <set>
int main ()
{
std::set<int> sut;
std::set<int>::iterator it;
std::pair<std::set<int>::iterator,bool> ret;
// Basic insert
sut.insert(7);
sut.insert(5);
sut.insert(12);
ret = sut.insert(23);
if (ret.second==true)
std::cout << "# 23 has been inserted!" << std::endl;
ret = sut.insert(23); // since it's a set and 23 is already present in it, this insert
should fail
if (ret.second==false)
std::cout << "# 23 already present in set!" << std::endl;
https://riptutorial.com/ 640
// Insert with hint for optimization
it = sut.end();
// This case is optimized for C++11 and above
// For earlier version, point to the element preceding your insertion
sut.insert(it, 30);
std::cout << std::endl << "Set under test contains:" << std::endl;
for (it = sut.begin(); it != sut.end(); ++it)
{
std::cout << *it << std::endl;
}
return 0;
}
12
20
23
30
45
All the insertion methods from sets also apply to multisets. Nevertheless, another possibility exists,
which is providing an initializer_list:
auto il = { 7, 5, 12 };
std::multiset<int> msut;
https://riptutorial.com/ 641
msut.insert(il);
setand multiset have default compare methods, but in some cases you may need to overload
them.
Let's imagine we are storing string values in a set, but we know those strings contain only numeric
values. By default the sort will be a lexicographical string comparison, so the order won't match
the numerical sort. If you want to apply a sort equivalent to what you would have with int values,
you need a functor to overload the compare method:
#include <iostream>
#include <set>
#include <stdlib.h>
int main ()
{
std::set<std::string> sut({"1", "2", "5", "23", "6", "290"});
std::cout << std::endl << "### Custom sort on set :" << std::endl;
for (auto &&data : sut_custom)
std::cout << data << std::endl;
auto compare_via_lambda = [](auto &&lhs, auto &&rhs){ return lhs > rhs; };
using set_via_lambda = std::set<std::string, decltype(compare_via_lambda)>;
set_via_lambda sut_reverse_via_lambda({"1", "2", "5", "23", "6", "290"},
compare_via_lambda);
std::cout << std::endl << "### Lambda sort on set :" << std::endl;
for (auto &&data : sut_reverse_via_lambda)
std::cout << data << std::endl;
return 0;
}
https://riptutorial.com/ 642
### Default sort on std::set<std::string> :
1
2
23
290
5
6
### Custom sort on set :
1
2
5
6
23
290
In the example above, one can find 3 different ways of adding compare operations to the std::set,
each of them is useful in its own context.
Default sort
This will use the compare operator of the key (first template argument). Often, the key will already
provide a good default for the std::less<T> function. Unless this function is specialized, it uses the
operator< of the object. This is especially useful when other code also tries to use some ordering,
as this allows consistency over the whole code base.
Writing the code this way, will reduce the effort to update your code when the key changes is API,
like: a class containing 2 members which changes to a class containing 3 members. By updating
the operator< in the class, all occurrences will get updated.
Custom sort
Adding a custom sort via an object with a compare operator is often used when the default
comparison doesn't comply. In the example above this is because the strings are referring to
integers. In other cases, it's often used when you want to compare (smart) pointers based upon
the object they refer to or because you need different constraints for comparing (example:
comparing std::pair by the value of first).
When creating a compare operator, this should be a stable sorting. If the result of the compare
operator changes after insert, you will have undefined behavior. As a good practice, your compare
operator should only use the constant data (const members, const functions ...).
As in the example above, you will often encounter classes without members as compare
https://riptutorial.com/ 643
operators. This results in default constructors and copy constructors. The default constructor
allows you to omit the instance at construction time and the copy constructor is required as the set
takes a copy of the compare operator.
Lambda sort
Lambdas are a shorter way to write function objects. This allows writing the compare operator on
less lines, making the overall code more readable.
The disadvantage of the use of lambdas is that each lambda gets a specific type at compile time,
so decltype(lambda) will be different for each compilation of the same compilation unit (cpp file) as
over multiple compilation units (when included via header file). For this reason, its recommended
to use function objects as compare operator when used within header files.
This construction is often encountered when a std::set is used within the local scope of a function
instead, while the function object is preferred when used as function arguments or class members.
To get the iterator of the first occurrence of a key, the find() function can be used. It returns end()
if the key does not exist.
std::set<int> sut;
sut.insert(10);
sut.insert(15);
sut.insert(22);
sut.insert(3); // contains 3, 10, 15, 22
std::multiset<int> msut;
sut.insert(10);
sut.insert(15);
sut.insert(22);
sut.insert(15);
sut.insert(3); // contains 3, 10, 15, 15, 22
https://riptutorial.com/ 644
Another way is using the count() function, which counts how many corresponding values have
been found in the set/multiset (in case of a set, the return value can be only 0 or 1). Using the
same values as above, we will have:
In the case of std::multiset, there could be several elements having the same value. To get this
range, the equal_range() function can be used. It returns std::pair having iterator lower bound
(inclusive) and upper bound (exclusive) respectively. If the key does not exist, both iterators would
point to the nearest superior value (based on compare method used to sort the given multiset).
The most obvious method, if you just want to reset your set/multiset to an empty one, is to use
clear:
std::set<int> sut;
sut.insert(10);
sut.insert(15);
sut.insert(22);
sut.insert(3);
sut.clear(); //size of sut is 0
Then the erase method can be used. It offers some possibilities looking somewhat equivalent to
the insertion:
std::set<int> sut;
std::set<int>::iterator it;
sut.insert(10);
sut.insert(15);
sut.insert(22);
sut.insert(3);
sut.insert(30);
sut.insert(33);
sut.insert(45);
// Basic deletion
sut.erase(3);
// Using iterator
it = sut.find(22);
sut.erase(it);
https://riptutorial.com/ 645
// Deleting a range of values
it = sut.find(33);
sut.erase(it, sut.end());
std::cout << std::endl << "Set under test contains:" << std::endl;
for (it = sut.begin(); it != sut.end(); ++it)
{
std::cout << *it << std::endl;
}
10
15
30
All those methods also apply to multiset. Please note that if you ask to delete an element from a
multiset, and it is present multiple times, all the equivalent values will be deleted.
https://riptutorial.com/ 646
Chapter 118: std::string
Introduction
Strings are objects that represent sequences of characters. The standard string class provides a
simple, safe and versatile alternative to using explicit arrays of chars when dealing with text and
other sequences of characters. The C++ string class is part of the std namespace and was
standardized in 1998.
Syntax
• // Empty string declaration
std::string s;
std::string s("Hello");
std::string s = "Hello";
std::string s1("Hello");
std::string s2(s1);
std::string s1("Hello");
https://riptutorial.com/ 647
Remarks
Before using std::string, you should include the header string, as it includes
functions/operators/overloads that other headers (for example iostream) do not include.
std::string oops(nullptr);
std::cout << oops << "\n";
The behavior of operator[] is a bit more complicated, in all cases it has undefined behavior if index
> size(), but when index == size():
C++11
C++11
Since C++14, instead of using "foo", it is recommended to use "foo"s, as s is a user-defined literal
suffix, which converts the const char* "foo" to std::string "foo".
Note: you have to use the namespace std::string_literals or std::literals to get the literal s.
Examples
Splitting
Use std::string::substr to split a string. There are two variants of this member function.
The first takes a starting position from which the returned substring should begin. The starting
position must be valid in the range (0, str.length()]:
The second takes a starting position and a total length of the new substring. Regardless of the
length, the substring will never go past the end of the source string:
https://riptutorial.com/ 648
std::string str = "Hello foo, bar and world!";
std::string newstr = str.substr(15, 3); // "and"
Note that you can also call substr with no arguments, in this case an exact copy of the string is
returned
String replacement
Replace by position
To replace a portion of a std::string you can use the method replace from std::string.
//Define string
std::string str = "Hello foo, bar and world!";
std::string alternate = "Hello foobar";
//1)
str.replace(6, 3, "bar"); //"Hello bar, bar and world!"
//2)
str.replace(str.begin() + 6, str.end(), "nobody!"); //"Hello nobody!"
//3)
str.replace(19, 5, alternate, 6, 6); //"Hello foo, bar and foobar!"
C++14
//4)
str.replace(19, 5, alternate, 6); //"Hello foo, bar and foobar!"
//5)
str.replace(str.begin(), str.begin() + 5, str.begin() + 6, str.begin() + 9);
//"foo foo, bar and world!"
//6)
str.replace(0, 5, 3, 'z'); //"zzz foo, bar and world!"
//7)
str.replace(str.begin() + 6, str.begin() + 9, 3, 'x'); //"Hello xxx, bar and world!"
C++11
//8)
str.replace(str.begin(), str.begin() + 5, { 'x', 'y', 'z' }); //"xyz foo, bar and world!"
https://riptutorial.com/ 649
Replace occurrences of a string with another
string
Replace only the first occurrence of replace with with in str:
Concatenation
You can concatenate std::strings using the overloaded + and += operators. Using the + operator:
https://riptutorial.com/ 650
You can also use push_back() to push back individual chars:
Accessing a character
There are several ways to extract characters from a std::string and each is subtly different.
operator[](n)
std::string::operator[] is not bounds-checked and does not throw an exception. The caller is
responsible for asserting that the index is within the range of the string:
at(n)
std::string::at is bounds checked, and will throw std::out_of_range if the index is not within the
range of the string:
C++11
Note: Both of these examples will result in undefined behavior if the string is empty.
front()
https://riptutorial.com/ 651
back()
Tokenize
1. str::strtok is the cheapest standard provided tokenization method, it also allows the
delimiter to be modified between tokens, but it incurs 3 difficulties with modern C++:
Generally any of these options cost will be hidden in the allocation cost of the tokens, but if
the cheapest algorithm is required and std::strtok's difficulties are not overcomable consider
a hand-spun solution.
// String to tokenize
std::string str{ "The quick brown fox" };
// Vector to store tokens
vector<std::string> tokens;
Live Example
2. The std::istream_iterator uses the stream's extraction operator iteratively. If the input
std::string is white-space delimited this is able to expand on the std::strtok option by
eliminating its difficulties, allowing inline tokenization thereby supporting the generation of a
const vector<string>, and by adding support for multiple delimiting white-space character:
// String to tokenize
const std::string str("The quick \tbrown \nfox");
std::istringstream is(str);
// Vector to store tokens
const std::vector<std::string> tokens = std::vector<std::string>(
std::istream_iterator<std::string>(is),
std::istream_iterator<std::string>());
https://riptutorial.com/ 652
Live Example
C++11
// String to tokenize
const std::string str{ "The ,qu\\,ick ,\tbrown, fox" };
const std::regex re{ "\\s*((?:[^\\\\,]|\\\\.)*?)\\s*(?:,|$)" };
// Vector to store tokens
const std::vector<std::string> tokens{
std::sregex_token_iterator(str.begin(), str.end(), re, 1),
std::sregex_token_iterator()
};
Live Example
In order to get const char* access to the data of a std::string you can use the string's c_str()
member function. Keep in mind that the pointer is only valid as long as the std::string object is
within scope and remains unchanged, that means that only const methods may be called on the
object.
C++17
The data() member function can be used to obtain a modifiable char*, which can be used to
manipulate the std::string object's data.
C++11
A modifiable char* can also be obtained by taking the address of the first character: &s[0]. Within
C++11, this is guaranteed to yield a well-formed, null-terminated string. Note that &s[0] is well-
formed even if s is empty, whereas &s.front() is undefined if s is empty.
C++11
// Copy the contents of str to untie lifetime from the std::string object
std::unique_ptr<char []> cstr = std::make_unique<char[]>(str.size() + 1);
https://riptutorial.com/ 653
cstr[str.size()] = '\0'; // A null-terminator needs to be added
// delete[] cstr_unsafe;
std::cout << cstr.get();
To find a character or another string, you can use std::string::find. It returns the position of the
first character of the first match. If no matches were found, the function returns std::string::npos
if (it != std::string::npos)
std::cout << "Found at position: " << it << '\n';
else
std::cout << "Not found!\n";
Found at position: 21
These functions can allow you to search for characters from the end of the string, as well as find
the negative case (ie. characters that are not in the string). Here is an example:
Found at position: 6
Note: Be aware that the above functions do not search for substrings, but rather for characters
contained in the search string. In this case, the last occurrence of 'g' was found at position 6 (the
other characters weren't found).
C++11
To trim a sequence or string means to remove all leading and trailing elements (or characters)
matching a certain predicate. We first trim the trailing elements, because it doesn't involve moving
any elements, and then trim the leading elements. Note that the generalizations below work for all
types of std::basic_string (e.g. std::string and std::wstring), and accidentally also for sequence
https://riptutorial.com/ 654
containers (e.g. std::vector and std::list).
Trimming the trailing elements involves finding the last element not matching the predicate, and
erasing from there on:
Trimming the leading elements involves finding the first element not matching the predicate and
erasing up to there:
To specialize the above for trimming whitespace in a std::string we can use the std::isspace()
function as a predicate:
If you wish to create a new sequence that is a trimmed copy, then you can use a separate
function:
https://riptutorial.com/ 655
trim(seq, pred);
return seq;
}
Lexicographical comparison
Two std::strings can be compared lexicographically using the operators ==, !=, <, <=, >, and >=:
All these functions use the underlying std::string::compare() method to perform the comparison,
and return for convenience boolean values. The operation of these functions may be interpreted
as follows, regardless of the actual implementation:
• operator==:
If str1.length() == str2.length() and each character pair matches, then returns true,
otherwise returns false.
• operator!=:
If str1.length() != str2.length() or one character pair doesn't match, returns true, otherwise
it returns false.
• operator< or operator>:
Finds the first different character pair, compares them then returns the boolean result.
• operator<= or operator>=:
Finds the first different character pair, compares them then returns the boolean result.
Note: The term character pair means the corresponding characters in both strings of the same
positions. For better understanding, if two example strings are str1 and str2, and their lengths are
n and m respectively, then character pairs of both strings means each str1[i] and str2[i] pairs
where i = 0, 1, 2, ..., max(n,m). If for any i where the corresponding character does not exist, that
is, when i is greater than or equal to n or m, it would be considered as the lowest value.
https://riptutorial.com/ 656
assert(str2 < str1);
Conversion to std::wstring
In C++, sequences of characters are represented by specializing the std::basic_string class with
a native character type. The two major collections defined by the standard library are std::string
and std::wstring:
#include <string>
#include <codecvt>
#include <locale>
std::string input_str = "this is a -string-, which is a sequence based on the -char- type.";
std::wstring input_wstr = L"this is a -wide- string, which is based on the -wchar_t- type.";
// conversion
std::wstring str_turned_to_wstr =
std::wstring_convert<std::codecvt_utf8<wchar_t>>().from_bytes(input_str);
std::string wstr_turned_to_str =
std::wstring_convert<std::codecvt_utf8<wchar_t>>().to_bytes(input_wstr);
In order to improve usability and/or readability, you can define functions to perform the conversion:
#include <string>
#include <codecvt>
#include <locale>
https://riptutorial.com/ 657
Sample usage:
Please note that char and wchar_t do not imply encoding, and gives no indication of size in bytes.
For instance, wchar_t is commonly implemented as a 2-bytes data type and typically contains UTF-
16 encoded data under Windows (or UCS-2 in versions prior to Windows 2000) and as a 4-bytes
data type encoded using UTF-32 under Linux. This is in contrast with the newer types char16_t
and char32_t, which were introduced in C++11 and are guaranteed to be large enough to hold any
UTF16 or UTF32 "character" (or more precisely, code point) respectively.
C++17
void foo(const char* s, size_t len); // pre-C++17, two arguments, have to pass them
// both everywhere
void foo(const char* s); // pre-C++17, single argument, but need to call
// strlen()
It offers a useful subset of the functionality that std::string does, although some of the functions
behave differently:
https://riptutorial.com/ 658
std::string str = "lllloooonnnngggg sssstttrrriiinnnggg"; //A really long string
//Bad way - 'string::substr' returns a new string (expensive if the string is long)
std::cout << str.substr(15, 10) << '\n';
C++11
std::string supports iterators, and so you can use a ranged based loop to iterate through each
character:
You can use a "traditional" for loop to loop through every character:
A std::string containing a number can be converted into an integer type, or a floating point type,
using conversion functions.
Note that all of these functions stop parsing the input string as soon as they encounter a non-
numeric character, so "123abc" will be converted into 123.
The std::ato* family of functions converts C-style strings (character arrays) to integer or floating-
point types:
C++11
However, use of these functions is discouraged because they return 0 if they fail to parse the
https://riptutorial.com/ 659
string. This is bad because 0 could also be a valid result, if for example the input string was "0", so
it is impossible to determine if the conversion actually failed.
The newer std::sto* family of functions convert std::strings to integer or floating-point types, and
throw exceptions if they could not parse their input. You should use these functions if possible:
C++11
Furthermore, these functions also handle octal and hex strings unlike the std::ato* family. The
second parameter is a pointer to the first unconverted character in the input string (not illustrated
here), and the third parameter is the base to use. 0 is automatic detection of octal (starting with 0)
and hex (starting with 0x or 0X), and any other value is the base to use
Converting between encodings is easy with C++11 and most compilers are able to deal with it in a
cross-platform manner through <codecvt> and <locale> headers.
#include <iostream>
#include <codecvt>
#include <locale>
#include <string>
using namespace std;
int main() {
// converts between wstring and utf8 string
wstring_convert<codecvt_utf8_utf16<wchar_t>> wchar_to_utf8;
// converts between u16string and utf8 string
wstring_convert<codecvt_utf8_utf16<char16_t>, char16_t> utf16_to_utf8;
https://riptutorial.com/ 660
cout << utf8str << endl;
wcout << wstr2 << endl;
return 0;
}
Mind that Visual Studio 2015 provides supports for these conversion but a bug in their library
implementation requires to use a different template for wstring_convert when dealing with char16_t:
C++14
In C++14, this is easily done by std::mismatch which returns the first mismatching pair from two
ranges:
Note that a range-and-a-half version of mismatch() existed prior to C++14, but this is unsafe in the
case that the second string is the shorter of the two.
C++14
We can still use the range-and-a-half version of std::mismatch(), but we need to first check that the
first string is at most as big as the second:
https://riptutorial.com/ 661
string.begin(), string.end()).first == prefix.end();
C++17
With std::string_view, we can write the direct comparison we want without having to worry about
allocation overhead or making copies:
Converting to std::string
#include <sstream>
int main()
{
int val = 4;
std::ostringstream str;
str << val;
std::string converted = str.str();
return 0;
}
template<class T>
std::string toString(const T& x)
{
std::ostringstream ss;
ss << x;
return ss.str();
}
C++11
https://riptutorial.com/ 662
Aside from streams, since C++11 you can also use the std::to_string (and std::to_wstring)
function which is overloaded for all fundamental types and returns the string representation of its
parameter.
https://riptutorial.com/ 663
Chapter 119: std::variant
Remarks
Variant is a replacement for raw union use. It is type-safe and knows what type it is, and it carefully
constructs and destroys the objects within it when it should.
It is almost never empty: only in corner cases where replacing its content throws and it cannot
back out safely does it end up being in an empty state.
Using std::get and std::get_if is usually a bad idea. The right answer is usually std::visit, which
lets you deal with every possibility right there. if constexpr can be used within the visit if you
need to branch your behavior, rather than doing a sequence of runtime checks that duplicate what
visit will do more efficiently.
Examples
Basic std::variant use
This creates a variant (a tagged union) that can store either an int or a string.
var = "hello"s;
// Prints "hello\n":
visit( [](auto&& e) {
std::cout << e << '\n';
}, var );
https://riptutorial.com/ 664
returns nullptr if you guess wrong.
Variants guarantee no dynamic memory allocation (other than which is allocated by their
contained types). Only one of the types in a variant is stored there, and in rare cases (involving
exceptions while assigning and no safe way to back out) the variant can become empty.
Variants let you store multiple value types in one variable safely and efficiently. They are basically
smart, type-safe unions.
template<class F>
struct pseudo_method {
F f;
// enable C++17 class type deduction:
pseudo_method( F&& fin ):f(std::move(fin)) {}
this creates a type that overloads operator->* with a Variant on the left hand side.
struct A {
void print( std::ostream& os ) const {
os << "A";
}
};
https://riptutorial.com/ 665
struct B {
void print( std::ostream& os ) const {
os << "B";
}
};
(var->*print)(std::cout);
and it will dispatch the call directly to A::print(std::cout) for us. If we instead initialized the var
with B{}, it would dispatch to B::print(std::cout).
struct C {};
then:
Extending the above would permit free function prints to be detected and used, possibly with use
of if constexpr within the print pseudo-method.
Constructing a `std::variant`
struct A {};
struct B { B()=default; B(B const&)=default; B(int){}; };
struct C { C()=delete; C(int) {}; C(C const&)=default; };
struct D { D( std::initializer_list<int> ) {}; D(D const&)=default; D()=default; };
https://riptutorial.com/ 666
Chapter 120: std::vector
Introduction
A vector is a dynamic array with automatically handled storage. The elements in a vector can be
accessed just as efficiently as those in an array with the advantage being that vectors can
dynamically change in size.
In terms of storage the vector data is (usually) placed in dynamically allocated memory thus
requiring some minor overhead; conversely C-arrays and std::array use automatic storage relative
to the declared location and thus do not have any overhead.
Remarks
Use of an std::vector requires the inclusion of the <vector> header using #include <vector>.
Elements in a std::vector are stored contiguously on the free store. It should be noted that when
vectors are nested as in std::vector<std::vector<int> >, the elements of each vector are
contiguous, but each vector allocates its own underlying buffer on the free store.
Examples
Initializing a std::vector
C++11
Copy construction (from another vector only), which copies data from v2:
std::vector<int> v(v2);
std::vector<int> v = v2;
C++11
https://riptutorial.com/ 667
Move construction (from another vector only), which moves data from v2:
std::vector<int> v(std::move(v2));
std::vector<int> v = std::move(v2);
// from an array
int z[] = { 1, 2, 3, 4 };
std::vector<int> v(z, z + 3); // v becomes {1, 2, 3}
// from a list
std::list<int> list1{ 1, 2, 3 };
std::vector<int> v(list1.begin(), list1.end()); // v becomes {1, 2, 3}
C++11
// from a list
std::list<int> list1{ 1, 2, 3 };
std::vector<int> v(std::make_move_iterator(list1.begin()),
std::make_move_iterator(list1.end()));
With the help of the assign() member function, a std::vector can be reinitialized after its
construction:
int z[] = { 1, 2, 3, 4 };
v.assign(z + 1, z + 4); // v becomes {2, 3, 4}
Inserting Elements
struct Point {
double x, y;
Point(double x, double y) : x(x), y(y) {}
};
std::vector<Point> v;
Point p(10.0, 2.0);
v.push_back(p); // p is copied into the vector.
C++11
https://riptutorial.com/ 668
Appending an element at the end of a vector by constructing the element in place:
std::vector<Point> v;
v.emplace_back(10.0, 2.0); // The arguments are passed to the constructor of the
// given type (here Point). The object is constructed
// in the vector, avoiding a copy.
Note that std::vector does not have a push_front() member function due to performance reasons.
Adding an element at the beginning causes all existing elements in the vector to be moved. If you
want to frequently insert elements at the beginning of your container, then you might want to use
std::list or std::deque instead.
std::vector<int> v{ 1, 2, 3 };
v.insert(v.begin(), 9); // v now contains {9, 1, 2, 3}
C++11
std::vector<int> v{ 1, 2, 3 };
v.emplace(v.begin()+1, 9); // v now contains {1, 9, 2, 3}
Use reserve() before inserting multiple elements if resulting vector size is known beforehand to
avoid multiple reallocations (see vector size and capacity):
std::vector<int> v;
v.reserve(100);
for(int i = 0; i < 100; ++i)
v.emplace_back(i);
Be sure to not make the mistake of calling resize() in this case, or you will inadvertently create a
vector with 200 elements where only the latter one hundred will have the value you intended.
https://riptutorial.com/ 669
Iterating Over std::vector
You can iterate over a std::vector in several ways. For each of the following sections, v is defined
as follows:
std::vector<int> v;
C++11
https://riptutorial.com/ 670
// Using for_each algorithm
// Note: Using a lambda for clarity. But a function or functor will work
std::for_each(std::rbegin(v), std::rend(v), [](auto const& value) {
std::cout << value << "\n";
});
Though there is no built-in way to use the range based for to reverse iterate; it is relatively simple
to fix this. The range based for uses begin() and end() to get iterators and thus simulating this with
a wrapper object can achieve the results we require.
C++14
template<class C>
struct ReverseRange {
C c; // could be a reference or a copy, if the original was a temporary
ReverseRange(C&& cin): c(std::forward<C>(cin)) {}
ReverseRange(ReverseRange&&)=default;
ReverseRange& operator=(ReverseRange&&)=delete;
auto begin() const {return std::rbegin(c);}
auto end() const {return std::rend(c);}
};
// C is meant to be deduced, and perfect forwarded into
template<class C>
ReverseRange<C> make_ReverseRange(C&& c) {return {std::forward<C>(c)};}
int main() {
std::vector<int> v { 1,2,3,4};
for(auto const& value: make_ReverseRange(v)) {
std::cout << value << "\n";
}
}
C++11
// forward iteration
for (auto pos = v.cbegin(); pos != v.cend(); ++pos) {
// type of pos is vector<T>::const_iterator
https://riptutorial.com/ 671
// *pos = 5; // Compile error - can't write via const iterator
}
// reverse iteration
for (auto pos = v.crbegin(); pos != v.crend(); ++pos) {
// type of pos is vector<T>::const_iterator
// *pos = 5; // Compile error - can't write via const iterator
}
// expects Functor::operand()(T&)
for_each(v.begin(), v.end(), Functor());
C++17
C++14
A Note on Efficiency
Since the class std::vector is basically a class that manages a dynamically allocated contiguous
array, the same principle explained here applies to C++ vectors. Accessing the vector's content by
index is much more efficient when following the row-major order principle. Of course, each access
to the vector also puts its management content into the cache as well, but as has been debated
many times (notably here and here), the difference in performance for iterating over a std::vector
compared to a raw array is negligible. So the same principle of efficiency for raw arrays in C also
applies for C++'s std::vector.
Accessing Elements
• index-based access
• iterators
https://riptutorial.com/ 672
Index-based access:
This can be done either with the subscript operator [], or the member function at().
Both return a reference to the element at the respective position in the std::vector (unless it's a
vector<bool>), so that it can be read as well as modified (if the vector is not const).
[] and at() differ in that [] is not guaranteed to perform any bounds checking, while at() does.
Accessing elements where index < 0 or index >= size is undefined behavior for [], while at()
throws a std::out_of_range exception.
Note: The examples below use C++11-style initialization for clarity, but the operators can be used
with all versions (unless marked C++11).
C++11
std::vector<int> v{ 1, 2, 3 };
// using []
int a = v[1]; // a is 2
v[1] = 4; // v now contains { 1, 4, 3 }
// using at()
int b = v.at(2); // b is 3
v.at(2) = 5; // v now contains { 1, 4, 5 }
int c = v.at(3); // throws std::out_of_range exception
Because the at() method performs bounds checking and can throw exceptions, it is slower than []
. This makes [] preferred code where the semantics of the operation guarantee that the index is in
bounds. In any case, accesses to elements of vectors are done in constant time. That means
accessing to the first element of the vector has the same cost (in time) of accessing the second
element, the third element and so on.
Here we know that the index variable i is always in bounds, so it would be a waste of CPU cycles
to check that i is in bounds for every call to operator[].
The front() and back() member functions allow easy reference access to the first and last element
of the vector, respectively. These positions are frequently used, and the special accessors can be
more readable than their alternatives using []:
https://riptutorial.com/ 673
int b = v.back(); // b is 6, v.back() is equivalent to v[v.size() - 1]
v.back() = 7; // v now contains {3, 5, 7}
Note: It is undefined behavior to invoke front() or back() on an empty vector. You need to check
that the container is not empty using the empty() member function (which checks if the container is
empty) before calling front() or back(). A simple example of the use of 'empty()' to test for an
empty vector follows:
int main ()
{
std::vector<int> v;
int sum (0);
std::cout << "total: " << sum << '\n';//output the total to the user
return 0;
}
The example above creates a vector with a sequence of numbers from 1 to 10. Then it pops the
elements of the vector out until the vector is empty (using 'empty()') to prevent undefined behavior.
Then the sum of the numbers in the vector is calculated and displayed to the user.
C++11
The data() method returns a pointer to the raw memory used by the std::vector to internally store
its elements. This is most often used when passing the vector data to legacy code that expects a
C-style array.
C++11
Before C++11, the data() method can be simulated by calling front() and taking the address of
the returned value:
std::vector<int> v(4);
int* ptr = &(v.front()); // or &v[0]
This works because vectors are always guaranteed to store their elements in contiguous memory
https://riptutorial.com/ 674
locations, assuming the contents of the vector doesn't override unary operator&. If it does, you'll
have to re-implement std::addressof in pre-C++11. It also assumes that the vector isn't empty.
Iterators:
Iterators are explained in more detail in the example "Iterating over std::vector" and the article
Iterators. In short, they act similarly to pointers to the elements of the vector:
C++11
std::vector<int> v{ 4, 5, 6 };
auto it = v.begin();
int i = *it; // i is 4
++it;
i = *it; // i is 5
*it = 6; // v contains { 4, 6, 6 }
auto e = v.end(); // e points to the element after the end of v. It can be
// used to check whether an iterator reached the end of the vector:
++it;
it == v.end(); // false, it points to the element at position 2 (with value 6)
++it;
it == v.end(); // true
It is consistent with the standard that a std::vector<T>'s iterators actually be T*s, but most standard
libraries do not do this. Not doing this both improves error messages, catches non-portable code,
and can be used to instrument the iterators with debugging checks in non-release builds. Then, in
release builds, the class wrapping around the underlying pointer is optimized away.
You can persist a reference or a pointer to an element of a vector for indirect access. These
references or pointers to elements in the vector remain stable and access remains defined unless
you add/remove elements at or before the element in the vector, or you cause the vector capacity
to change. This is the same as the rule for invalidating iterators.
C++11
std::vector<int> v{ 1, 2, 3 };
int* p = v.data() + 1; // p points to 2
v.insert(v.begin(), 0); // p is now invalid, accessing *p is a undefined behavior.
p = v.data() + 1; // p points to 1
v.reserve(10); // p is now invalid, accessing *p is a undefined behavior.
p = v.data() + 1; // p points to 1
v.erase(v.begin()); // p is now invalid, accessing *p is a undefined behavior.
There are several ways to use a std::vector as a C array (for example, for compatibility with C
libraries). This is possible because the elements in a vector are stored contiguously.
C++11
https://riptutorial.com/ 675
std::vector<int> v{ 1, 2, 3 };
int* p = v.data();
In contrast to solutions based on previous C++ standards (see below), the member function
.data() may also be applied to empty vectors, because it doesn't cause undefined behavior in this
case.
Before C++11, you would take the address of the vector's first element to get an equivalent
pointer, if the vector isn't empty, these both methods are interchangeable:
Note: If the vector is empty, v[0] and v.front() are undefined and cannot be used.
When storing the base address of the vector's data, note that many operations (such as push_back,
resize, etc.) can change the data memory location of the vector, thus invalidating previous data
pointers. For example:
std::vector<int> v;
int* p = v.data();
v.resize(42); // internal memory location changed; value of p is now invalid
Iterator/Pointer Invalidation
Iterators and pointers pointing into an std::vector can become invalid, but only when performing
certain operations. Using invalid iterators/pointers will result in undefined behavior.
• Any insertion operation which changes the capacity of the vector will invalidate all
iterators/pointers:
C++11
https://riptutorial.com/ 676
• Any insertion operation, which does not increase the capacity, will still invalidate
iterators/pointers pointing to elements at the insertion position and past it. This includes the
end iterator:
vector<int> v(5);
v.reserve(20); // Capacity is at least 20.
int *p1 = &v[0];
int *p2 = &v[3];
v.insert(v.begin() + 2, 5, 0); // `p2` is invalidated, but since the capacity
// did not change, `p1` remains valid.
int *p3 = &v[v.size() - 1];
v.push_back(10); // The capacity did not change, so `p3` and `p1` remain valid.
• Any removal operation will invalidate iterators/pointers pointing to the removed elements and
to any elements past the removed elements. This includes the end iterator:
vector<int> v(10);
int *p1 = &v[0];
int *p2 = &v[5];
v.erase(v.begin() + 3, v.end()); // `p2` is invalid, but `p1` remains valid.
• operator= (copy, move, or otherwise) and clear() will invalidate all iterators/pointers pointing
into the vector.
Deleting Elements
Note: For a vector deleting an element which is not the last element, all elements beyond the
deleted element have to be copied or moved to fill the gap, see the note below and std::list.
https://riptutorial.com/ 677
Deleting all elements in a range:
std::vector<int> v{ 1, 2, 3, 4, 5, 6 };
v.erase(v.begin() + 1, v.begin() + 5); // v becomes {1, 6}
Note: The above methods do not change the capacity of the vector, only the size. See Vector Size
and Capacity.
The erase method, which removes a range of elements, is often used as a part of the erase-
remove idiom. That is, first std::remove moves some elements to the end of the vector, and then
erase chops them off. This is a relatively inefficient operation for any indices less than the last
index of the vector because all elements after the erased segments must be relocated to new
positions. For speed critical applications that require efficient removal of arbitrary elements in a
container, see std::list.
std::vector<int> v{ 1, 2, 3, 4, 5, 6 };
v.erase(std::remove_if(v.begin(), v.end(),
[](auto& element){return element > 3;} ), v.end()
);
https://riptutorial.com/ 678
Deleting elements by condition from a loop:
std::vector<int> v{ 1, 2, 3, 4, 5, 6 };
std::vector<int>::iterator it = v.begin();
while (it != v.end()) {
if (condition)
it = v.erase(it); // after erasing, 'it' will be set to the next element in v
else
++it; // manually set 'it' to the next element in v
}
While it is important not to increment it in case of a deletion, you should consider using a different
method when then erasing repeatedly in a loop. Consider remove_if for a more efficient way.
• Given a reverse iterator it pointing to some element, the method base gives the regular (non-
reverse) iterator pointing to the same element.
Put altogether, the line it = rev_itr(v.erase(it.base())) says: take the reverse iterator it, have v
erase the element pointed by its regular iterator; take the resulting iterator, construct a reverse
iterator from it, and assign it to the reverse iterator it.
Deleting all elements using v.clear() does not free up memory (capacity() of the vector remains
unchanged). To reclaim space, use:
https://riptutorial.com/ 679
std::vector<int>().swap(v);
C++11
v.shrink_to_fit();
The shrink_to_fit does not guarantee to really reclaim space, but most current implementations
do.
The function std::find, defined in the <algorithm> header, can be used to find an element in a
std::vector.
std::finduses the operator== to compare elements for equality. It returns an iterator to the first
element in the range that compares equal to the value.
If the element in question is not found, std::find returns std::vector::end (or std::vector::cend if
the vector is const).
C++11
C++11
std::vector<int> v { 5, 4, 3, 2, 1 };
If you need to perform many searches in a large vector, then you may want to consider sorting the
vector first, before using the binary_search algorithm.
To find the first element in a vector that satisfies a condition, std::find_if can be used. In addition
to the two parameters given to std::find, std::find_if accepts a third argument which is a function
https://riptutorial.com/ 680
object or function pointer to a predicate function. The predicate should accept an element from the
container as an argument and return a value convertible to bool, without modifying the container:
C++11
struct moreThan {
moreThan(int limit) : _limit(limit) {}
int _limit;
};
C++11
An array can easily be converted into a std::vector by using std::begin and std::end:
C++11
for(auto &x: v)
std::cout << x << " ";
std::cout << std::endl;
12345
https://riptutorial.com/ 681
std::vector<std::string> args(argv, argv + argc);
}
The standard (section 23.3.7) specifies that a specialization of vector<bool> is provided, which
optimizes space by packing the bool values, so that each takes up only one bit. Since bits aren't
addressable in C++, this means that several requirements on vector are not placed on
vector<bool>:
C++11
Similarly, functions expecting a bool& argument cannot be used with the result of operator [] or
at() applied to vector<bool>, or with the result of dereferencing its iterator:
The implementation of std::vector<bool> is dependent on both the compiler and architecture. The
specialisation is implemented by packing n Booleans into the lowest addressable section of
memory. Here, n is the size in bits of the lowest addressable memory. In most modern systems
this is 1 byte or 8 bits. This means that one byte can store 8 Boolean values. This is an
improvement over the traditional implementation where 1 Boolean value is stored in 1 byte of
memory.
Note: The below example shows possible bitwise values of individual bytes in a traditional vs.
optimized vector<bool>. This will not always hold true in all architectures. It is, however, a good
way of visualising the optimization. In the below examples a byte is represented as [x, x, x, x, x, x,
x, x].
https://riptutorial.com/ 682
Traditional std::vector<char> storing 8 Boolean values:
C++11
std::vector<char> trad_vect = {true, false, false, false, true, false, true, true};
Bitwise representation:
C++11
std::vector<bool> optimized_vect = {true, false, false, false, true, false, true, true};
Bitwise representation:
[1,0,0,0,1,0,1,1]
Notice in the above example, that in the traditional version of std::vector<bool>, 8 Boolean values
take up 8 bytes of memory, whereas in the optimized version of std::vector<bool>, they only use 1
byte of memory. This is a significant improvement on memory usage. If you need to pass a
vector<bool> to an C-style API, you may need to copy the values to an array, or find a better way
to use the API, if memory and performance are at risk.
1. Current vector size is queried by size() member function. Convenience empty() function
returns true if size is 0:
vector<int> v = { 1, 2, 3 }; // size is 3
const vector<int>::size_type size = v.size();
cout << size << endl; // prints 3
cout << boolalpha << v.empty() << endl; // prints false
vector<int> v; // size is 0
cout << v.size() << endl; // prints 0
4. Removing N elements from vector decreases size by N (e.g. by pop_back(), erase() or clear()
functions).
https://riptutorial.com/ 683
5. Vector has an implementation-specific upper limit on its size, but you are likely to run out of
RAM before reaching it:
vector<int> v;
const vector<int>::size_type max_size = v.max_size();
cout << max_size << endl; // prints some large number
v.resize( max_size ); // probably won't work
v.push_back( 1 ); // definitely won't work
// !!!bad!!!evil!!!
vector<int> v_bad( N, 1 ); // constructs large N size vector
for( int i = 0; i < v_bad.size(); ++i ) { // size is not supposed to be int!
do_something( v_bad[i] );
}
Vector capacity differs from size. While size is simply how many elements the vector currently
has, capacity is for how many elements it allocated/reserved memory for. That is useful, because
too frequent (re)allocations of too large sizes can be expensive.
2. You can manually reserve capacity by reserve( N ) function (it changes vector capacity to N):
// !!!bad!!!evil!!!
vector<int> v_bad;
for( int i = 0; i < 10000; ++i ) {
v_bad.push_back( i ); // possibly lot of reallocations
}
// good
vector<int> v_good;
v_good.reserve( 10000 ); // good! only one allocation
for( int i = 0; i < 10000; ++i ) {
v_good.push_back( i ); // no allocations needed anymore
}
3. You can request for the excess capacity to be released by shrink_to_fit() (but the
implementation doesn't have to obey you). This is useful to conserve used memory:
Vector partly manages capacity automatically, when you add elements it may decide to grow.
https://riptutorial.com/ 684
Implementers like to use 2 or 1.5 for the grow factor (golden ratio would be the ideal value - but is
impractical due to being rational number). On the other hand vector usually do not automatically
shrink. For example:
Concatenating Vectors
One std::vector can be append to another by using the member function insert():
However, this solution fails if you try to append a vector to itself, because the standard specifies
that iterators given to insert() must not be from the same range as the receiver object's elements.
c++11
Instead of using the vector's member functions, the functions std::begin() and std::end() can be
used:
This is a more general solution, for example, because b can also be an array. However, also this
solution doesn't allow you to append a vector to itself.
If the order of the elements in the receiving vector doesn't matter, considering the number of
elements in each vector can avoid unnecessary copy operations:
A std::vector automatically increases its capacity upon insertion as needed, but it never reduces
its capacity after element removal.
https://riptutorial.com/ 685
// Initialize a vector with 100 elements
std::vector<int> v(100);
To reduce its capacity, we can copy the contents of a vector to a new temporary vector. The new
vector will have the minimum capacity that is needed to store all elements of the original vector. If
the size reduction of the original vector was significant, then the capacity reduction for the new
vector is likely to be significant. We can then swap the original vector with the temporary one to
retain its minimized capacity:
std::vector<int>(v).swap(v);
C++11
In C++11 we can use the shrink_to_fit() member function for a similar effect:
v.shrink_to_fit();
Note: The shrink_to_fit() member function is a request and doesn't guarantee to reduce capacity.
The <algorithm> header provides a number of useful functions for working with sorted vectors.
An important prerequisite for working with sorted vectors is that the stored values are comparable
with <.
std::vector<int> v;
// add some code here to fill v with some elements
std::sort(v.begin(), v.end());
Sorted vectors allow efficient element lookup using the function std::lower_bound(). Unlike
std::find(), this performs an efficient binary search on the vector. The downside is that it only
gives valid results for sorted input ranges:
Note: If the requested value is not part of the vector, std::lower_bound() will return an iterator to
https://riptutorial.com/ 686
the first element that is greater than the requested value. This behavior allows us to insert a new
element at its right place in an already sorted vector:
If you need to insert a lot of elements at once, it might be more efficient to call push_back() for all
them first and then call std::sort() once all elements have been inserted. In this case, the
increased cost of the sorting can pay off against the reduced cost of inserting new elements at the
end of the vector and not in the middle.
If your vector contains multiple elements of the same value, std::lower_bound() will try to return an
iterator to the first element of the searched value. However, if you need to insert a new element
after the last element of the searched value, you should use the function std::upper_bound() as this
will cause less shifting around of elements:
If you need both the upper bound and the lower bound iterators, you can use the function
std::equal_range() to retrieve both of them efficiently with one call:
std::pair<std::vector<int>::iterator,
std::vector<int>::iterator> rg = std::equal_range(v.begin(), v.end(), 42);
std::vector<int>::iterator lower_bound = rg.first;
std::vector<int>::iterator upper_bound = rg.second;
In order to test whether an element exists in a sorted vector (although not specific to vectors), you
can use the function std::binary_search():
C++11
In C++11, compilers are required to implicitly move from a local variable that is being returned.
Moreover, most compilers can perform copy elision in many cases and elide the move altogether.
As a result of this, returning large objects that can be moved cheaply no longer requires special
handling:
#include <vector>
#include <iostream>
https://riptutorial.com/ 687
}
return v; // implicit move
}
// print vector
for (auto value : vec)
std::cout << value << " "; // this will print "1 2 3 4 5 6 7 8 9 10 "
return 0;
}
C++11
Before C++11, copy elision was already allowed and implemented by most compilers. However,
due to the absence of move semantics, in legacy code or code that has to be compiled with older
compiler versions which don't implement this optimization, you can find vectors being passed as
output arguments to prevent the unneeded copy:
#include <vector>
#include <iostream>
// fill vector
fillVectorFrom_By_Ref(1, 10, vec);
// print vector
for (std::vector<int>::const_iterator it = vec.begin(); it != vec.end(); ++it)
std::cout << *it << " "; // this will print "1 2 3 4 5 6 7 8 9 10 "
std::cout << std::endl;
return 0;
}
To find the largest or smallest element stored in a vector, you can use the methods
std::max_element and std::min_element, respectively. These methods are defined in <algorithm>
header. If several elements are equivalent to the greatest (smallest) element, the methods return
the iterator to the first such element. Return v.end() for empty vectors.
https://riptutorial.com/ 688
int maxElement = *std::max_element(v.begin(), v.end());
std::cout << "maxElementIndex:" << maxElementIndex << ", maxElement:" << maxElement << '\n';
std::cout << "minElementIndex:" << minElementIndex << ", minElement:" << minElement << '\n';
Output:
maxElementIndex:3, maxElement:10
minElementIndex:1, minElement:2
C++11
The minimum and maximum element in a vector can be retrieved at the same time by using the
method std::minmax_element, which is also defined in <algorithm> header:
Output:
minimum element: 2
maximum element: 10
A matrix with 3 rows and 4 columns with each cell initialised as 0 can be defined as:
C++11
The syntax for initializing them using initialiser lists or otherwise are similar to that of a normal
vector.
https://riptutorial.com/ 689
Iterating over the entire matrix is similar to that of a normal vector but with an extra dimension.
C++11
A vector of vectors is a convenient way to represent a matrix but it's not the most efficient:
individual vectors are scattered around memory and the data structure isn't cache friendly.
Also, in a proper matrix, the length of every row must be the same (this isn't the case for a vector
of vectors). The additional flexibility can be a source of errors.
https://riptutorial.com/ 690
Chapter 121: Storage class specifiers
Introduction
Storage class specifiers are keywords that can be used in declarations. They do not affect the type
of the declaration, but typically modify the way in which the entity is stored.
Remarks
There are six storage class specifiers, although not all in the same version of the language: auto
(until C++11), register (until C++17), static, thread_local (since C++11), extern, and mutable.
A declaration may contain no storage class specifier. In that case, the language specifies a default
behaviour. For example, by default, a variable declared at block scope implicitly has automatic
storage duration.
Examples
mutable
A specifier that can be applied to the declaration of a non-static, non-reference data member of a
class. A mutable member of a class is not const even when the object is const.
class C {
int x;
mutable int times_accessed;
public:
C(): x(0), times_accessed(0) {
}
int get_x() const {
++times_accessed; // ok: const member function can modify mutable data member
return x;
}
void set_x(int x) {
++times_accessed;
this->x = x;
}
};
C++11
A second meaning for mutable was added in C++11. When it follows the parameter list of a
lambda, it suppresses the implicit const on the lambda's function call operator. Therefore, a
https://riptutorial.com/ 691
mutable lambda can modify the values of entities captured by copy. See mutable lambdas for
more details.
Note that mutable is not a storage class specifier when used this way to form a mutable lambda.
register
C++17
A storage class specifier that hints to the compiler that a variable will be heavily used. The word
"register" is related to the fact that a compiler might choose to store such a variable in a CPU
register so that it can be accessed in fewer clock cycles. It was deprecated starting in C++11.
register int i = 0;
while (i < 100) {
f(i);
int g = i*i;
i += h(i, g);
}
Both local variables and function parameters may be declared register. Unlike C, C++ does not
place any restrictions on what can be done with a register variable. For example, it is valid to take
the address of a register variable, but this may prevent the compiler from actually storing such a
variable in a register.
C++17
The keyword register is unused and reserved. A program that uses the keyword register is ill-
formed.
static
https://riptutorial.com/ 692
2. Declares a variable to have static storage duration (unless it is thread_local). Namespace-
scope variables are implicitly static. A static local variable is initialized only once, the first
time control passes through its definition, and is not destroyed every time its scope is exited.
void f() {
static int count = 0;
std::cout << "f has been called " << ++count << " times so far\n";
}
3. When applied to the declaration of a class member, declares that member to be a static
member.
struct S {
static S* create() {
return new S;
}
};
int main() {
S* s = S::create();
}
Note that in the case of a static data member of a class, both 2 and 3 apply simultaneously: the
static keyword both makes the member into a static data member and makes it into a variable
with static storage duration.
auto
C++03
Declares a variable to have automatic storage duration. It is redundant, since automatic storage
duration is already the default at block scope, and the auto specifier is not allowed at namespace
scope.
void f() {
auto int x; // equivalent to: int x;
auto y; // illegal in C++; legal in C89
}
auto int z; // illegal: namespace-scope variable cannot be automatic
In C++11, auto changed meaning completely, and is no longer a storage class specifier, but is
instead used for type deduction.
extern
The extern storage class specifier can modify a declaration in one of the three following ways,
depending on context:
1. It can be used to declare a variable without defining it. Typically, this is used in a header file
for a variable that will be defined in a separate implementation file.
https://riptutorial.com/ 693
// global scope
int x; // definition; x will be default-initialized
extern int y; // declaration; y is defined elsewhere, most likely another TU
extern int z = 42; // definition; "extern" has no effect here (compiler may warn)
2. It gives external linkage to a variable at namespace scope even if const or constexpr would
have otherwise caused it to have internal linkage.
// global scope
const int w = 42; // internal linkage in C++; external linkage in C
static const int x = 42; // internal linkage in both C++ and C
extern const int y = 42; // external linkage in both C++ and C
namespace {
extern const int z = 42; // however, this has internal linkage since
// it's in an unnamed namespace
}
3. It redeclares a variable at block scope if it was previously declared with linkage. Otherwise, it
declares a new variable with linkage, which is a member of the nearest enclosing
namespace.
// global scope
namespace {
int x = 1;
struct C {
int x = 2;
void f() {
extern int x; // redeclares namespace-scope x
std::cout << x << '\n'; // therefore, this prints 1, not 2
}
};
}
void g() {
extern int y; // y has external linkage; refers to global y defined elsewhere
}
A function can also be declared extern, but this has no effect. It is usually used as a hint to the
reader that a function declared here is defined in another translation unit. For example:
In the above code, if f were changed to extern and g to non-extern, it would not affect the
correctness or semantics of the program at all, but would likely confuse the reader of the code.
https://riptutorial.com/ 694
Chapter 122: Stream manipulators
Introduction
Manipulators are special helper functions that help controlling input and output streams using
operator >> or operator <<.
Remarks
Manipulators can be used in other way. For example:
str.setf(base == 8 ? std::ios_base::oct :
base == 10 ? std::ios_base::dec :
base == 16 ? std::ios_base::hex :
std::ios_base::fmtflags(0),
std::ios_base::basefield);
6. std::ios_base::basefield.
For flags: dec, hex and oct:
https://riptutorial.com/ 695
• os.setf(std::ios_base::flag, std::ios_base::basefield); equals to os << std::flag;
is.setf(std::ios_base::flag, std::ios_base::basefield); equals to is >> std::flag;
(1)
• str.unsetf(std::ios_base::flag, std::ios_base::basefield); equals to
str.setf(std::ios_base::fmtflags(0), std::ios_base::basefield);
(2)
7. std::ios_base::adjustfield.
For flags: left, right and internal:
8. std::ios_base::floatfield.
Examples
https://riptutorial.com/ 696
Stream manipulators
bool boolValue;
std::cin >> std::boolalpha >> boolValue;
std::cout << "Value \"" << std::boolalpha << boolValue
<< "\" was parsed as " << std::noboolalpha << boolValue;
// Input: true
// Output: Value "true" was parsed as 0
std::showbase and std::noshowbase - control whether prefix indicating numeric base is used.
std::dec (decimal), std::hex (hexadecimal) and std::oct (octal) - are used for changing base for
integers.
#include <sstream>
If you want to see more about std::istringstream check out the <sstream> header.
Default is std::nouppercase.
https://riptutorial.com/ 697
std::setw(n) - changes the width of the next input/output field to exactly n.
The width property n is resetting to 0 when some functions are called (full list is here).
// Output: 51
// setw(7): 51
// setw(7), more output: 13*****67 94
Default is std::setw(0).
std::left, std::right and std::internal - modify the default position of the fill characters by setting
std::ios_base::adjustfield to std::ios_base::left, std::ios_base::right and
std::ios_base::internal correspondingly. std::left and std::right apply to any output,
std::internal - for integer, floating-point and monetary output. Have no effect on input streams.
#include <locale>
...
std::cout.imbue(std::locale("en_US.utf8"));
https://riptutorial.com/ 698
// Output:
// flt: -**********9.87
// hex: *************41
// $: $3.67**********
// usd: USD *******3.67
// usd: USD 3.67
Default is std::left.
fmtflags
#include <sstream>
...
double f;
std::istringstream is("0x1P-1022");
double f = std::strtod(is.str().c_str(), NULL);
std::cout << "Parsing 0x1P-1022 as hex gives " << f << '\n';
// Output:
// The number 0.01 in fixed: 0.070000
// The number 0.01 in scientific: 7.000000e-02
// The number 0.01 in hexfloat: 0x1.1eb851eb851ecp-4
// The number 0.01 in default: 0.07
// Parsing 0x1P-1022 as hex gives 2.22507e-308
Default is std::ios_base::fmtflags(0).
https://riptutorial.com/ 699
There is a bug on some compilers which causes
double f;
std::istringstream("0x1P-1022") >> std::hexfloat >> f;
std::cout << "Parsing 0x1P-1022 as hex gives " << f << '\n';
// Output: Parsing 0x1P-1022 as hex gives 0
std::showpoint and std::noshowpoint - control whether decimal point is always included in floating-
point representation. Have no effect on input streams.
std::cout << "7.0 with showpoint: " << std::showpoint << 7.0 << '\n'
<< "7.0 with noshowpoint: " << std::noshowpoint << 7.0 << '\n';
// Output: 1.0 with showpoint: 7.00000
// 1.0 with noshowpoint: 7
Default is std::showpoint.
std::showpos and std::noshowpos - control displaying of the + sign in non-negative output. Have no
effect on input streams.
Default if std::noshowpos.
std::unitbuf, std::nounitbuf- control flushing output stream after every operation. Have no effect
on input stream. std::unitbuf causes flushing.
https://riptutorial.com/ 700
std::setprecision(n) - changes floating-point precision.
#include <cmath>
#include <limits>
...
// Output:
// default precision (6): pi: 3.14159
// 10pi: 31.4159
// std::setprecision(4): 10pi: 31.42
// 10000pi: 3.142e+04
// std::fixed: 10000pi: 31415.9265
// std::setprecision(10): pi: 3.141592654
// max-1 radix precicion: pi:
3.14159265358979323851280895940618620443274267017841339111328125
// max+1 radix precision: pi:
3.14159265358979323851280895940618620443274267017841339111328125
// significant digits prec: pi: 3.14159265358979324
Default is std::setprecision(6).
#include <sstream>
...
https://riptutorial.com/ 701
std::cout << "Parsing \"10 010\" with autodetect gives: " << num1 << ' ' << num2 << '\n';
// Parsing "10 010" with autodetect gives: 10 8
std::skipws and std::noskipws - control skipping of leading whitespace by the formatted input
functions. Have no effect on output streams.
#include <sstream>
...
Default is std::ios_base::skipws.
std::quoted(s[, delim[, escape]]) [C++14] - inserts or extracts quoted strings with embedded
spaces.
#include <sstream>
...
std::stringstream ss;
std::string in = "String with spaces, and embedded \"quotes\" too";
std::string out;
ss << std::quoted(in);
std::cout << "read in [" << in << "]\n"
<< "stored as [" << ss.str() << "]\n";
ss >> std::quoted(out);
std::cout << "written out [" << out << "]\n";
// Output:
// read in [String with spaces, and embedded "quotes" too]
// stored as ["String with spaces, and embedded \"quotes\" too"]
// written out [String with spaces, and embedded "quotes" too]
https://riptutorial.com/ 702
Output stream manipulators
std::ends - inserts a null character '\0' to output stream. More formally this manipulator's
declaration looks like
and this manipulator places character by calling os.put(charT()) when used in an expression
os << std::ends;
std::endland std::flush both flush output stream out by calling out.flush(). It causes immediately
producing output. But std::endl inserts end of line '\n' symbol before flushing.
std::cout << "First line." << std::endl << "Second line. " << std::flush
<< "Still second line.";
// Output: First line.
// Second line. Still second line.
std::cout << "\nDefault fill: " << std::setw(10) << 79 << '\n'
<< "setfill('#'): " << std::setfill('#')
<< std::setw(10) << 42 << '\n';
// Output:
// Default fill: 79
// setfill('#'): ########79
std::cout.imbue(std::locale("en_US.utf8"));
std::cout << std::showbase << "en_US: " << std::put_money(money)
<< " or " << std::put_money(money, true) << '\n';
// Output: en_US: $1.23 or USD 1.23
std::cout.imbue(std::locale("ru_RU.utf8"));
std::cout << "ru_RU: " << std::put_money(money)
<< " or " << std::put_money(money, true) << '\n';
// Output: ru_RU: 1.23 руб or 1.23 RUB
std::cout.imbue(std::locale("ja_JP.utf8"));
https://riptutorial.com/ 703
std::cout << "ja_JP: " << std::put_money(money)
<< " or " << std::put_money(money, true) << '\n';
// Output: ja_JP: 123 or JPY 123
std::put_time(tmb, fmt) [C++11] - formats and outputs a date/time value to std::tm according to
the specified format fmt.
tmb - pointer to the calendar time structure const std::tm* as obtained from localtime() or gmtime().
fmt - pointer to a null-terminated string const CharT* specifying the format of conversion.
#include <ctime>
...
std::time_t t = std::time(nullptr);
std::tm tm = *std::localtime(&t);
std::cout.imbue(std::locale("ru_RU.utf8"));
std::cout << "\nru_RU: " << std::put_time(&tm, "%c %Z") << '\n';
// Possible output:
// ru_RU: Вт 04 июл 2017 15:08:35 UTC
#include <sstream>
...
std::string str;
std::istringstream(" \v\n\r\t Wow!There is no whitespaces!") >> std::ws >> str;
std::cout << str;
// Output: Wow!There is no whitespaces!
#include <sstream>
#include <locale>
...
in.imbue(std::locale("en_US.UTF-8"));
https://riptutorial.com/ 704
in >> std::get_money(v1) >> std::get_money(v2) >> std::get_money(v3, true);
if (in) {
std::cout << std::quoted(in.str()) << " parsed as: "
<< v1 << ", " << v2 << ", " << v3 << '\n';
}
// Output:
// "$1,234.56 2.22 USD 3.33" parsed as: 123456, 222, 333
std::get_time(tmb, fmt) [C++11] - parses a date/time value stored in tmb of specified format fmt.
tmb - valid pointer to the const std::tm* object where the result will be stored.
fmt - pointer to a null-terminated string const CharT* specifying the conversion format.
#include <sstream>
#include <locale>
...
std::tm t = {};
std::istringstream ss("2011-Februar-18 23:12:34");
ss.imbue(std::locale("de_DE.utf-8"));
ss >> std::get_time(&t, "%Y-%b-%d %H:%M:%S");
if (ss.fail()) {
std::cout << "Parse failed\n";
}
else {
std::cout << std::put_time(&t, "%c") << '\n';
}
// Possible output:
// Sun Feb 18 23:12:34 2011
https://riptutorial.com/ 705
Chapter 123: Templates
Introduction
Classes, functions, and (since C++14) variables can be templated. A template is a piece of code
with some free parameters that will become a concrete class, function, or variable when all
parameters are specified. Parameters can be types, values, or themselves templates. A well-
known template is std::vector, which becomes a concrete container type when the element type is
specified, e.g., std::vector<int>.
Syntax
• template < template-parameter-list > declaration
• export template < template-parameter-list > declaration /* until C++11 */
• template <> declaration
• template declaration
• extern template declaration /* since C++11 */
• template < template-parameter-list > class ...(opt) identifier(opt)
• template < template-parameter-list > class identifier(opt) = id-expression
• template < template-parameter-list > typename ...(opt) identifier(opt) /* since C++17 */
• template < template-parameter-list > typename identifier(opt) = id-expression /* since C++17
*/
• postfix-expression . template id-expression
• postfix-expression -> template id-expression
• nested-name-specifier template simple-template-id ::
Remarks
The word template is a keyword with five different meanings in the C++ language, depending on
the context.
1. When followed by a list of template parameters enclosed in <>, it declares a template such
as a class template, a function template, or a partial specialization of an existing template.
https://riptutorial.com/ 706
printf("%s\n", s);
}
template std::set<int> make_singleton(int x); // <-- keyword used in this sense here
5. After the scope resolution operator :: and the class member access operators . and ->, it
specifies that the following name is a template.
struct Allocator {
template <class T>
T* allocate();
};
Before C++11, a template could be declared with the export keyword, making it into an exported
template. An exported template's definition does not need to be present in every translation unit in
which the template is instantiated. For example, the following was supposed to work:
foo.h:
https://riptutorial.com/ 707
#ifndef FOO_H
#define FOO_H
export template <class T> T identity(T x);
#endif
foo.cpp:
#include "foo.h"
template <class T> T identity(T x) { return x; }
main.cpp:
#include "foo.h"
int main() {
const int x = identity(42); // x is 42
}
Due to difficulty of implementation, the export keyword was not supported by most major
compilers. It was removed in C++11; now, it is illegal to use the export keyword at all. Instead, it is
usually necessary to define templates in headers (in contrast to non-template functions, which are
usually not defined in headers). See Why can templates only be implemented in the header file?
Examples
Function Templates
Templating can also be applied to functions (as well as the more traditional structures) with the
same effect.
printSum<int>(4, 5);
printSum<float>(4.5f, 8.9f);
In both these case the template argument is used to replace the types of the parameters; the
result works just like a normal C++ function (if the parameters don't match the template type the
compiler applies the standard conversions).
One additional property of template functions (unlike template classes) is that the compiler can
infer the template parameters based on the parameters passed to the function.
https://riptutorial.com/ 708
printSum(4, 5); // Both parameters are int.
// This allows the compiler deduce that the type
// T is also int.
printSum(5.0, 4); // In this case the parameters are two different types.
// The compiler is unable to deduce the type of T
// because there are contradictions. As a result
// this is a compile time error.
This feature allows us to simplify code when we combine template structures and functions. There
is a common pattern in the standard library that allows us to make template structure X using a
helper function make_X().
auto val1 = MyPair<int, float>{5, 8.7}; // Create object explicitly defining the types
auto val2 = make_MyPair(5, 8.7); // Create object using the types of the paramters.
// In this code both val1 and val2 are the same
// type.
Note: This is not designed to shorten the code. This is designed to make the code more robust. It
allows the types to be changed by changing the code in a single place rather than in multiple
locations.
Argument forwarding
Template may accept both lvalue and rvalue references using forwarding reference:
In this case, the real type of t will be deduced depending on the context:
struct X { };
X x;
f(x); // calls f<X&>(x)
https://riptutorial.com/ 709
f(X()); // calls f<X>(x)
In the first case, the type T is deduced as reference to X (X&), and the type of t is lvalue reference
to X, while in the second case the type of T is deduced as X and the type of t as rvalue reference to
X (X&&).
Note: It is worth noticing that in the first case, decltype(t) is the same as T, but not in the second.
In order to perfectly forward t to another function ,whether it is an lvalue or rvalue reference, one
must use std::forward:
Note: Forwarding references can only be used for template parameters, for instance, in the
following code, v is a rvalue reference, not a forwarding reference:
#include <vector>
The basic idea of a class template is that the template parameter gets substituted by a type at
compile time. The result is that the same class can be reused for multiple types. The user
specifies which type will be used when a variable of the class is declared. Three examples of this
are shown in main():
#include <iostream>
using std::cout;
template <typename T> // A simple class to hold one number of any type
class Number {
public:
void setNum(T n); // Sets the class field to the given number
T plus1() const; // returns class field's "follower"
private:
T num; // Class field
};
template <typename T> // Set the class field to the given number
void Number<T>::setNum(T n) {
https://riptutorial.com/ 710
num = n;
}
int main() {
Number<int> anInt; // Test with an integer (int replaces T in the class)
anInt.setNum(1);
cout << "My integer + 1 is " << anInt.plus1() << "\n"; // Prints 2
Template Specialization
template<>
int sqrt<int>(int i) { /* Highly optimized integer implementation */ }
Then a user that writes sqrt(4.0) will get the generic implementation whereas sqrt(4) will get the
specialized implementation.
// Common case:
template<typename T, typename U>
struct S {
T t_val;
U u_val;
};
https://riptutorial.com/ 711
// Special case when the first template argument is fixed to int
template<typename V>
struct S<int, V> {
double another_value;
int foo(double arg) {// Do something}
};
As shown above, partial template specializations may introduce completely different sets of data
and function members.
When a partially specialized template is instantiated, the most suitable specialization is selected.
For example, let's define a template and two partial specializations:
template<typename V>
struct S<int, double, V> {
static void foo() {
std::cout << "T = int, U = double\n";
}
};
will print
General case
T = int
T = int, U = double
// OK.
template<>
https://riptutorial.com/ 712
void foo<int, int>(int a1, int a2) {
std::cout << "Two ints: " << a1 << " " << a2 << std::endl;
}
void invoke_foo() {
foo(1, 2.1); // Prints "General case: 1 2.1"
foo(1,2); // Prints "Two ints: 1 2"
}
Just like in case of the function arguments, template parameters can have their default values. All
template parameters with a default value have to be declared at the end of the template parameter
list. The basic idea is that the template parameters with default value can be omitted while
template instantiation.
int main() {
/* Default parameter is ignored, N = 5 */
my_array<int, 5> a;
Alias template
C++11
Basic example:
https://riptutorial.com/ 713
Alias templates cannot be specialized. However, that functionality can be obtained indirectly by
having them refer to a nested type in a struct:
template<typename T>
struct nonconst_pointer_helper { typedef T* type; };
template<typename T>
struct nonconst_pointer_helper<T const> { typedef T* type; };
Sometimes we would like to pass into the template a template type without fixing its values. This is
what template template parameters are created for. Very simple template template parameter
examples:
int main() {
IntTag<Tag1>::type t;
}
C++11
#include <vector>
#include <iostream>
int main() {
std::vector<float> vf = {1.2, 2.6, 3.7};
auto vi = cast_all<int>(vf);
for(auto &&i: vi) {
std::cout << i << std::endl;
}
}
Prior to C++17, when writing a template non-type parameter, you had to specify its type first. So a
common pattern became writing something like:
https://riptutorial.com/ 714
template <class T, T N>
struct integral_constant {
using type = T;
static constexpr T value = N;
};
But for complicated expressions, using something like this involves having to write decltype(expr),
expr when instantiating templates. The solution is to simplify this idiom and simply allow auto:
C++17
A nice motivating example can come from trying to combine the empty base optimization with a
custom deleter for unique_ptr. Different C API deleters have different return types, but we don't
care - we just want something to work for any function:
And now you can simply use any function pointer that can take an argument of type T as a
template non-type parameter, regardless of return type, and get a no-size overhead unique_ptr out
of it:
unique_ptr_deleter<std::FILE, std::fclose> p;
Apart from types as a template parameter we are allowed to declare values of constant
expressions meeting one of the following criteria:
https://riptutorial.com/ 715
• pointer to member,
• std::nullptr_t.
Like all template parameters, non-type template parameters can be explicitly specified, defaulted,
or derived implicitly via Template Argument Deduction.
#include <iostream>
int main()
{
char anArrayOfChar[15];
std::cout << "anArrayOfChar: " << size_of(anArrayOfChar) << "\n";
#include <array>
int main ()
{
std::array<int, 5> foo; // int is a type parameter, 5 is non-type
}
Non-type template parameters are one of the ways to achieve template recurrence and enables to
do Metaprogramming.
C++14
It is often useful to define classes or structures that have a variable number and type of data
members which are defined at compile time. The canonical example is std::tuple, but sometimes
is it is necessary to define your own custom structures. Here is an example that defines the
structure using compounding (rather than inheritance as with std::tuple. Start with the general
(empty) definition, which also serves as the base-case for recrusion termination in the later
specialisation:
This already allows us to define an empty structure, DataStructure<> data, albeit that isn't very
useful yet.
https://riptutorial.com/ 716
Next comes the recursive case specialisation:
T first;
DataStructure<Rest ... > rest;
};
This is now sufficient for us to create arbitrary data structures, like DataStructure<int, float,
std::string> data(1, 2.1, "hello").
So what's going on? First, note that this is a specialisation whose requirement is that at least one
variadic template parameter (namely T above) exists, whilst not caring about the specific makeup
of the pack Rest. Knowing that T exists allows the definition of its data member, first. The rest of
the data is recursively packaged as DataStructure<Rest ... > rest. The constructor initiates both of
those members, including a recursive constructor call to the rest member.
To understand this better, we can work through an example: suppose you have a declaration
DataStructure<int, float> data. The declaration first matches against the specialisation, yielding a
structure with int first and DataStructure<float> rest data members. The rest definition again
matches this specialisation, creating its own float first and DataStructure<> rest members.
Finally this last rest matches against the base-case defintion, producing an empty structure.
DataStructure<int, float>
-> int first
-> DataStructure<float> rest
-> float first
-> DataStructure<> rest
-> (empty)
Now we have the data structure, but its not terribly useful yet as we cannot easily access the
individual data elements (for example to access the last member of DataStructure<int, float,
std::string> data we would have to use data.rest.rest.first, which is not exactly user-friendly).
So we add a get method to it (only needed in the specialisation as the base-case structure has no
data to get):
https://riptutorial.com/ 717
...
};
As you can see this get member function is itself templated - this time on the index of the member
that is needed (so usage can be things like data.get<1>(), similar to std::tuple). The actual work is
done by a static function in a helper class, GetHelper. The reason we can't define the required
functionality directly in DataStructure's get is because (as we will shortly see) we would need to
specialise on idx - but it isn't possible to specialise a template member function without
specialising the containing class template. Note also the use of a C++14-style auto here makes
our lives significantly simpler as otherwise we would need quite a complicated expression for the
return type.
So on to the helper class. This time we will need an empty forward declaration and two
specialisations. First the declaration:
Now the base-case (when idx==0). In this case we just return the first member:
In the recursive case, we decrement idx and invoke the GetHelper for the rest member:
To work through an example, suppose we have DataStructure<int, float> data and we need
data.get<1>(). This invokes GetHelper<1, DataStructure<int, float>>::get(data) (the 2nd
specialisation), which in turn invokes GetHelper<0, DataStructure<float>>::get(data.rest), which
finally returns (by the 1st specialisation as now idx is 0) data.rest.first.
So that's it! Here is the whole functioning code, with some example use in the main function:
#include <iostream>
https://riptutorial.com/ 718
template<typename ... T>
struct DataStructure
{
};
T first;
DataStructure<Rest ... > rest;
template<size_t idx>
auto get()
{
return GetHelper<idx, DataStructure<T,Rest...>>::get(*this);
}
};
int main()
{
DataStructure<int, float, std::string> data(1, 2.1, "Hello");
return 0;
}
Explicit instantiation
An explicit instantiation definition creates and declares a concrete class, function, or variable from
a template, without using it just yet. An explicit instantiation can be referenced from other
translation units. This can be used to avoid defining a template in a header file, if it will only be
instantiated with a finite set of arguments. For example:
https://riptutorial.com/ 719
// print_string.h
template <class T>
void print_string(const T* str);
// print_string.cpp
#include "print_string.h"
template void print_string(const char*);
template void print_string(const wchar_t*);
C++11
foo.h
#ifndef FOO_H
#define FOO_H
template <class T> void foo(T x) {
// complicated implementation
}
#endif
foo.cpp
#include "foo.h"
// explicit instantiation definitions for common cases
template void foo(int);
template void foo(double);
main.cpp
#include "foo.h"
// we already know foo.cpp has explicit instantiation definitions for these
extern template void foo(double);
int main() {
foo(42); // instantiates foo<int> here;
// wasteful since foo.cpp provides an explicit instantiation already!
foo(3.14); // does not instantiate foo<double> here;
// uses instantiation of foo<double> in foo.cpp instead
}
https://riptutorial.com/ 720
Chapter 124: The ISO C++ Standard
Introduction
In 1998, the there was a first publication of the standard making C++ an internally standardized
language. From that time, C++ has evolved resulting in different dialects of C++. On this page, you
can find an overview of all different standards and their changes compared to the previous
version. The details on how to use these features is described on more specialized pages.
Remarks
When C++ is mentioned, often a reference is made to "the Standard". But what is exactly that
standard?
C++ has a long history. Started as a small project by Bjarne Stroustrup within Bell Labs, by the
early 90's it had become quite popular. Multiple companies were creating C++ compilers so that
users could run their C++ compilers on a wide range of computers. But in order to facilitate this, all
these competing compilers should share a single definition of the language.
At that point, the C language had successfully been standardized. This means that a formal
description of the language was written. This was submitted to the American National Standards
Institute (ANSI), which opened up the document for review and subsequently published it in 1989.
One year later, the International Organization for Standards (Because it would have different
acronyms in different languages they chose one form, ISO, derived from the Greek isos, meaning
equal.) adopted the American standard as an International Standard.
For C++, it was clear from the beginning that there was an international interest. A workgroup
within ISO was started (known as WG21, within SubCommittee 22). This workgroup drafted a first
standard around 1995. But as we programmers know, there's nothing more dangerous to a
planned delivery than last minute features, and that happened to C++ as well. In 1995, a cool new
library named the STL surfaced, and the people working in WG21 decided to add a slimmed-down
version to the C++ draft standard. Naturally, this caused the deadlines to be missed and only 3
years later did the document become final. ISO is a very formal organization, so the C++ Standard
was christened with the not very marketable name of ISO/IEC 14882. As standards can be
updated, this exact version became known as 14882:1998.
And indeed there was a demand to update the Standard. The Standard is a very thick document,
which aims to exactly describe how C++ compilers should work. Even a slight ambiguity can be
worth fixing, so by 2003 an update was released as 14882:2003. However, this did not add any
feature to C++; the new features were scheduled for the second update.
Informally, this second update was known as C++0x, because it wasn't known whether this would
take until 2008 or 2009. Well - that version also got a slight delay, which is why it became
14882:2011.
Luckily, WG21 decided not to let that happen again. C++11 was well-received and let to a
https://riptutorial.com/ 721
renewed interest in C++. So, to keep the momentum, the third update went from planning to
publishing in 3 years, to become 14882:2014.
The work didn't stop there, either. The C++17 standard has been proposed and the work for
C++20 has been started.
Examples
Current Working Drafts
All published ISO standards are available for sale from the ISO store ( http://www.iso.org ). The
working drafts of the C++ standards are publicly available for free though.
C++11
The C++11 standard is a major extension to the C++ standard. Below you can find an overview of
the changes as they have been grouped on the isocpp FAQ with links to more detailed
documentation.
Language Extensions
General Features
• auto
• decltype
• Range-for statement
• Initializer lists
• Uniform initialization syntax and semantics
• Rvalue references and move semantics
• Lambdas
• noexcept to prevent exception propagation
• constexpr
• nullptr – a null pointer literal
• Copying and rethrowing exceptions
• Inline namespaces
• User-defined literals
https://riptutorial.com/ 722
Classes
• =default and =delete
• Control of default move and copy
• Delegating constructors
• In-class member initializers
• Inherited constructors
• Override controls: override
• Override controls: final
• Explicit conversion operators
Other Types
• enum class
• long long – a longer integer
• Extended integer types
• Generalized unions
• Generalized PODs
Templates
• Extern templates
• Template aliases
• Variadic templates
• Local types as template arguments
Concurrency
• Concurrency memory model
• Dynamic initialization and destruction with concurrency
• Thread-local storage
https://riptutorial.com/ 723
Library Extensions
General
• unique_ptr
• shared_ptr
• weak_ptr
• Garbage collection ABI
• tuple
• Type traits
• function and bind
• Regular Expressions
• Time utilities
• Random number generation
• Scoped allocators
Concurrency
• Threads
• Mutual exclusion
• Locks
• Condition variables
• Atomics
• Futures and promises
• async
• Abandoning a process
C++14
The C++14 standard is often referred to as a bugfix for C++11. It contains only a limited list of
changes of which most are extensions to the new features in C++11. Below you can find an
overview of the changes as they have been grouped on the isocpp FAQ with links to more detailed
documentation.
Language Extensions
https://riptutorial.com/ 724
• Binary literals
• Generalized return type deduction
• decltype(auto)
• Generalized lambda captures
• Generic lambdas
• Variable templates
• Extended constexpr
• The [[deprecated]] attribute
• Digit separators
Library Extensions
• Shared locking
• User-defined literals for std:: types
• std::make_unique
• Type transformation _t aliases
• Addressing tuples by type (e.g. get<string>(t))
• Transparent Operator Functors (e.g. greater<>(x))
• std::quoted
Deprecated / Removed
• std::gets was deprecated in C++11 and removed from C++14
• std::random_shuffle is deprecated
C++17
The C++17 standard is feature complete and has been proposed for standardization. In compilers
with experimental support for these features, it is usually referred to as C++1z.
Language Extensions
• Fold Expressions
• declaring non-type template arguments with auto
• Guaranteed copy elision
• Template parameter deduction for constructors
• Structured bindings
• Compact nested namespaces
• New attributes: [[fallthrough]], [[nodiscard]], [[maybe_unused]]
• Default message for static_assert
• Initializers in if and switch
• Inline variables
• if constexpr
• Order of expression evaluation guarantees
https://riptutorial.com/ 725
• Dynamic memory allocation for over-aligned data
Library Extensions
• std::optional
• std::variant
• std::string_view
• merge() and extract() for associative containers
• A file system library with the <filesystem> header.
• Parallel versions of most of the standard algorithms (in the <algorithm> header).
• Addition of mathematical special functions in the <cmath> header.
• Moving nodes between map<>, unordered_map<>, set<>, and unordered_set<>
C++03
The C++03 standard mainly addresses defect reports of the C++98 standard. Apart from these
defects, it only adds one new feature.
Language Extensions
• Value initalization
C++98
C++98 is the first standardized version of C++. As it was developed as an extension to C, many of
the features which set apart C++ from C are added.
Library Extensions
• The Standard Template Library
https://riptutorial.com/ 726
C++20
C++20 is the upcoming standard of C++, currently in development, based upon the C++17
standard. It's progress can be tracked on the official ISO cpp website.
The following features are simply what has been accepted for the next release of the C++
standard, targeted for 2020.
Language Extensions
No language extensions have been accepted for now.
Library Extensions
No library extensions have been accepted for now.
https://riptutorial.com/ 727
Chapter 125: The Rule of Three, Five, And
Zero
Examples
Rule of Five
C++11
C++11 introduces two new special member functions: the move constructor and the move
assignment operator. For all the same reasons that you want to follow the Rule of Three in C++03,
you usually want to follow the Rule of Five in C++11: If a class requires ONE of five special
member functions, and if move semantics are desired, then it most likely requires ALL FIVE of
them.
Note, however, that failing to follow the Rule of Five is usually not considered an error, but a
missed optimisation opportunity, as long as the Rule of Three is still followed. If no move
constructor or move assignment operator is available when the compiler would normally use one,
it will instead use copy semantics if possible, resulting in a less efficient operation due to
unnecessary copy operations. If move semantics aren't desired for a class, then it has no need to
declare a move constructor or assignment operator.
class Person
{
char* name;
int age;
public:
// Destructor
~Person() { delete [] name; }
https://riptutorial.com/ 728
// This allows certain optimizations in the standard library
// when the class is used in a container.
Alternatively, both the copy and move assignment operator can be replaced with a single
assignment operator, which takes an instance by value instead of reference or rvalue reference to
facilitate using the copy-and-swap idiom.
Extending from the Rule of Three to the Rule of Five is important for performance reasons, but is
not strictly necessary in most cases. Adding the copy constructor and assignment operator
ensures that moving the type will not leak memory (move-constructing will simply fall back to
copying in that case), but will be performing copies that the caller probably did not anticipate.
Rule of Zero
C++11
We can combine the principles of the Rule of Five and RAII to get a much leaner interface: the
Rule of Zero: any resource that needs to be managed should be in its own type. That type would
have to follow the Rule of Five, but all users of that resource do not need to write any of the five
special member functions and can simply default all of them.
Using the Person class introduced in the Rule of Three example, we can create a resource-
managing object for cstrings:
class cstring {
private:
char* p;
https://riptutorial.com/ 729
public:
~cstring() { delete [] p; }
cstring(cstring const& );
cstring(cstring&& );
cstring& operator=(cstring const& );
cstring& operator=(cstring&& );
And once this is separate, our Person class becomes far simpler:
class Person {
cstring name;
int arg;
public:
~Person() = default;
Person(Person const& ) = default;
Person(Person&& ) = default;
Person& operator=(Person const& ) = default;
Person& operator=(Person&& ) = default;
The special members in Person do not even need to be declared explicitly; the compiler will default
or delete them appropriately, based on the contents of Person. Therefore, the following is also an
example of the rule of zero.
struct Person {
cstring name;
int arg;
};
If cstring were to be a move-only type, with a deleted copy constructor/assignment operator, then
Person would automatically be move-only as well.
Rule of Three
c++03
The Rule of Three states that if a type ever needs to have a user-defined copy constructor, copy
assignment operator, or destructor, then it must have all three.
The reason for the rule is that a class which needs any of the three manages some resource (file
handles, dynamically allocated memory, etc), and all three are needed to manage that resource
consistently. The copy functions deal with how the resource gets copied between objects, and the
destructor would destroy the resource, in accord with RAII principles.
https://riptutorial.com/ 730
class Person
{
char* name;
int age;
public:
Person(char const* new_name, int new_age)
: name(new char[std::strlen(new_name) + 1])
, age(new_age)
{
std::strcpy(name, new_name);
}
~Person() {
delete [] name;
}
};
Since name was allocated in the constructor, the destructor deallocates it to avoid leaking memory.
But what happens if such an object is copied?
int main()
{
Person p1("foo", 11);
Person p2 = p1;
}
First, p1 will be constructed. Then p2 will be copied from p1. However, the C++-generated copy
constructor will copy each component of the type as-is. Which means that p1.name and p2.name
both point to the same string.
When main ends, destructors will be called. First p2's destructor will be called; it will delete the
string. Then p1's destructor will be called. However, the string is already deleted. Calling delete on
memory that was already deleted yields undefined behavior.
To avoid this, it is necessary to provide a suitable copy constructor. One approach is to implement
a reference counted system, where different Person instances share the same string data. Each
time a copy is performed, the shared reference count is incremented. The destructor then
decrements the reference count, only releasing the memory if the count is zero.
https://riptutorial.com/ 731
}
Implementation of the copy assignment operator is complicated by the need to release an existing
buffer. The copy and swap technique creates a temporary object which holds a new buffer.
Swapping the contents of *this and copy gives ownership to copy of the original buffer. Destruction
of copy, as the function returns, releases the buffer previously owned by *this.
Self-assignment Protection
When writing a copy assignment operator, it is very important that it be able to work in the event of
self-assignment. That is, it has to allow this:
SomeType t = ...;
t = t;
Self-assignment usually doesn't happen in such an obvious way. It typically happens via a
circuitous route through various code systems, where the location of the assignment simply has
two Person pointers or references and has no idea that they are the same object.
Any copy assignment operator you write must be able to take this into account.
The typical way to do so is to wrap all of the assignment logic in a condition like this:
Note: It is important to think about self-assignment and ensure that your code behaves correctly
when it happens. However, self-assignment is a very rare occurrence and optimizing to prevent it
may actually pessimize the normal case. Since the normal case is much more common,
pessimizing for self-assignment may well reduce your code efficiency (so be careful using it).
As an example, the normal technique for implementing the assignment operator is the copy and
swap idiom. The normal implementation of this technique does not bother to test for self-
assignment (even though self-assignment is expensive because a copy is made). The reason is
that pessimization of the normal case has been shown to be much more costly (as it happens
more often).
c++11
Move assignment operators must also be protected against self-assignment. However, the logic
for many such operators is based on std::swap, which can handle swapping from/to the same
memory just fine. So if your move assignment logic is nothing more than a series of swap
operations, then you do not need self-assignment protection.
https://riptutorial.com/ 732
If this is not the case, you must take similar measures as above.
https://riptutorial.com/ 733
Chapter 126: The This Pointer
Remarks
The this pointer is a keyword for C++ therfore there is no library needed to implement this. And do
not forget this is a pointer! So you cannot do:
this.someMember();
As you access member functions or member variables from pointers using the arrow symbol -> :
this->someMember();
http://www.geeksforgeeks.org/this-pointer-in-c/
https://www.tutorialspoint.com/cplusplus/cpp_this_pointer.htm
Examples
this Pointer
All non-static member functions have a hidden parameter, a pointer to an instance of the class,
named this; this parameter is silently inserted at the beginning of the parameter list, and handled
entirely by the compiler. When a member of the class is accessed inside a member function, it is
silently accessed through this; this allows the compiler to use a single non-static member function
for all instances, and allows a member function to call other member functions polymorphically.
struct ThisPointer {
int i;
ThisPointer(int ii);
https://riptutorial.com/ 734
if (some_external_condition) {
set_i(182);
} else {
i = 218;
}
}
// Compiler rewrites as:
/* virtual */ void ThisPointer::func(ThisPointer* this) {
if (some_external_condition) {
this->set_i(182);
} else {
this->i = 218;
}
}
In a constructor, this can safely be used to (implicitly or explicitly) access any field that has
already been initialised, or any field in a parent class; conversely, (implicitly or explicitly) accessing
any fields that haven't yet been initialised, or any fields in a derived class, is unsafe (due to the
derived class not yet being constructed, and thus its fields neither being initialised nor existing). It
is also unsafe to call virtual member functions through this in the constructor, as any derived class
functions will not be considered (due to the derived class not yet being constructed, and thus its
constructor not yet updating the vtable).
Also note that while in a constructor, the type of the object is the type which that constructor
constructs. This holds true even if the object is declared as a derived type. For example, in the
below example, ctd_good and ctd_bad are type CtorThisBase inside CtorThisBase(), and type CtorThis
inside CtorThis(), even though their canonical type is CtorThisDerived. As the more-derived classes
are constructed around the base class, the instance gradually goes through the class hierarchy
until it is a fully-constructed instance of its intended type.
class CtorThisBase {
short s;
public:
CtorThisBase() : s(516) {}
};
public:
// Good constructor.
CtorThis() : i(s + 42), j(this->i), k(j) {}
// Bad constructor.
CtorThis(int ii) : i(ii), j(this->k), k(b ? 51 : -51) {
virt_func();
https://riptutorial.com/ 735
}
public:
CtorThisDerived() : b(true) {}
CtorThisDerived(int ii) : CtorThis(ii), b(false) {}
// ...
CtorThisDerived ctd_good;
CtorThisDerived ctd_bad(3);
In this context, using the this pointer isn't entirely necessary, but it will make your code clearer to
the reader, by indicating that a given function or variable is a member of the class. An example in
this situation:
using std::cout;
using std::endl;
class Class
https://riptutorial.com/ 736
{
public:
Class();
~Class();
int getPrivateNumber () const;
private:
int private_number = 42;
};
Class::Class(){}
Class::~Class(){}
int main()
{
Class class_example;
cout << class_example.getPrivateNumber() << endl;
}
Using the this Pointer to Differentiate Between Member Data and Parameters
This is an actual useful strategy to differentiate member data from parameters... Lets take this
example :
using std::cout;
using std::endl;
/*
* @class Dog
* @member name
* Dog's name
* @function bark
* Dog Barks!
* @function getName
* To Get Private
* Name Variable
*/
class Dog
{
public:
Dog(std::string name);
~Dog();
void bark() const;
std::string getName() const;
private:
std::string name;
};
https://riptutorial.com/ 737
Dog::Dog(std::string name)
{
/*
* this->name is the
* name variable from
* the class dog . and
* name is from the
* parameter of the function
*/
this->name = name;
}
Dog::~Dog(){}
int main()
{
Dog dog("Max");
cout << dog.getName() << endl;
dog.bark();
}
this->name = name;
Here , you can see we are assinging the parameter name to the name of the private variable from
the class Dog(this->name) .
this can also be cv-qualified, the same as any other pointer. However, due to the this parameter
not being listed in the parameter list, special syntax is required for this; the cv-qualifiers are listed
after the parameter list, but before the function's body.
struct ThisCVQ {
void no_qualifier() {} // "this" is: ThisCVQ*
void c_qualifier() const {} // "this" is: const ThisCVQ*
void v_qualifier() volatile {} // "this" is: volatile ThisCVQ*
void cv_qualifier() const volatile {} // "this" is: const volatile ThisCVQ*
};
https://riptutorial.com/ 738
struct CVOverload {
int func() { return 3; }
int func() const { return 33; }
int func() volatile { return 333; }
int func() const volatile { return 3333; }
};
When this is const (including const volatile), the function is unable to write to member variables
through it, whether implicitly or explicitly. The sole exception to this is mutable member variables,
which can be written regardless of const-ness. Due to this, const is used to indicate that the
member function doesn't change the object's logical state (the way the object appears to the
outside world), even if it does modify the physical state (the way the object looks under the hood).
Logical state is the way the object appears to outside observers. It isn't directly tied to
physical state, and indeed, might not even be stored as physical state. As long as
outside observers can't see any changes, the logical state is constant, even if you flip
every single bit in the object.
Physical state, also known as bitwise state, is how the object is stored in memory. This
is the object's nitty-gritty, the raw 1s and 0s that make up its data. An object is only
physically constant if its representation in memory never changes.
Note that C++ bases constness on logical state, not physical state.
class DoSomethingComplexAndOrExpensive {
mutable ResultType cached_result;
mutable bool state_changed;
ResultType calculate_result();
void modify_somehow(const Param& p);
// ...
public:
DoSomethingComplexAndOrExpensive(Param p) : state_changed(true) {
modify_somehow(p);
}
void change_state(Param p) {
modify_somehow(p);
state_changed = true;
}
if (state_changed) {
cached_result = calculate_result();
https://riptutorial.com/ 739
state_changed = false;
}
return cached_result;
}
Note that while you technically could use const_cast on this to make it non-cv-qualified, you really,
REALLY shouldn't, and should use mutable instead. A const_cast is liable to invoke undefined
behaviour when used on an object that actually is const, while mutable is designed to be safe to
use. It is, however, possible that you may run into this in extremely old code.
An exception to this rule is defining non-cv-qualified accessors in terms of const accessors; as the
object is guaranteed to not be const if the non-cv-qualified version is called, there's no risk of UB.
class CVAccessor {
int arr[5];
public:
const int& get_arr_element(size_t i) const { return arr[i]; }
int& get_arr_element(size_t i) {
return const_cast<int&>(const_cast<const CVAccessor*>(this)->get_arr_element(i));
}
};
As with regular pointers, if this is volatile (including const volatile), it is loaded from memory
each time it is accessed, instead of being cached. This has the same effects on optimisation as
declaring any other pointer volatile would, so care should be taken.
Note that if an instance is cv-qualified, the only member functions it is allowed to access are
member functions whose this pointer is at least as cv-qualified as the instance itself:
struct CVAccess {
void func() {}
void func_c() const {}
void func_v() volatile {}
void func_cv() const volatile {}
};
CVAccess cva;
cva.func(); // Good.
cva.func_c(); // Good.
https://riptutorial.com/ 740
cva.func_v(); // Good.
cva.func_cv(); // Good.
C++11
Similarly to this cv-qualifiers, we can also apply ref-qualifiers to *this. Ref-qualifiers are used to
choose between normal and rvalue reference semantics, allowing the compiler to use either copy
or move semantics depending on which are more appropriate, and are applied to *this instead of
this.
Note that despite ref-qualifiers using reference syntax, this itself is still a pointer. Also note that
ref-qualifiers don't actually change the type of *this; it's just easier to describe and understand
their effects by looking at them as if they did.
struct RefQualifiers {
std::string s;
// Normal version.
void func() & { std::cout << "Accessed on normal instance " << s << std::endl; }
// Rvalue version.
void func() && { std::cout << "Accessed on temporary instance " << s << std::endl; }
// ...
RefQualifiers rf("Fred");
rf.func(); // Output: Accessed on normal instance Fred
RefQualifiers{}.func(); // Output: Accessed on temporary instance The nameless one
A member function cannot have overloads both with and without ref-qualifiers; the programmer
has to choose between one or the other. Thankfully, cv-qualifiers can be used in conjunction with
https://riptutorial.com/ 741
ref-qualifiers, allowing const correctness rules to be followed.
struct RefCV {
void func() & {}
void func() && {}
void func() const& {}
void func() const&& {}
void func() volatile& {}
void func() volatile&& {}
void func() const volatile& {}
void func() const volatile&& {}
};
https://riptutorial.com/ 742
Chapter 127: Thread synchronization
structures
Introduction
Working with threads might need some synchronization techniques if the threads interact. In this
topic, you can find the different structures which are provided by the standard library to solve these
issues.
Examples
std::shared_lock
A shared_lock can be used in conjunction with a unique lock to allow multiple readers and
exclusive writers.
#include <unordered_map>
#include <mutex>
#include <shared_mutex>
#include <thread>
#include <string>
#include <iostream>
class PhoneBook {
public:
string getPhoneNo( const std::string & name )
{
shared_lock<shared_timed_mutex> r(_protect);
auto it = _phonebook.find( name );
if ( it == _phonebook.end() )
return (*it).second;
return "";
}
void addPhoneNo ( const std::string & name, const std::string & phone )
{
unique_lock<shared_timed_mutex> w(_protect);
_phonebook[name] = phone;
}
shared_timed_mutex _protect;
unordered_map<string,string> _phonebook;
};
std::call_once, std::once_flag
https://riptutorial.com/ 743
#include <mutex>
#include <iostream>
std::once_flag flag;
void do_something(){
std::call_once(flag, [](){std::cout << "Happens once" << std::endl;});
Often you want to lock the entire object while you perform multiple operations on it. For example, if
you need to examine or modify the object using iterators. Whenever you need to call multiple
member functions it is generally more efficient to lock the whole object rather than individual
member functions.
For example:
class text_buffer
{
// for readability/maintainability
using mutex_type = std::shared_timed_mutex;
using reading_lock = std::shared_lock<mutex_type>;
using updates_lock = std::unique_lock<mutex_type>;
public:
// This returns a scoped lock that can be shared by multiple
// readers at the same time while excluding any writers
[[nodiscard]]
reading_lock lock_for_reading() const { return reading_lock(mtx); }
private:
char buf[1024];
mutable mutex_type mtx; // mutable allows const objects to be locked
};
When calculating a checksum the object is locked for reading, allowing other threads that want to
read from the object at the same time to do so.
https://riptutorial.com/ 744
std::size_t checksum(text_buffer const& buf)
{
std::size_t sum = 0xA44944A4;
for(auto c: buf)
sum = (sum << 8) | (((unsigned char) ((sum & 0xFF000000) >> 24)) ^ c);
return sum;
}
Clearing the object updates its internal data so it must be done using an exclusing lock.
When obtaining more than one lock care should be taken to always acquire the locks in the same
order for all threads.
std::condition_variable_any, std::cv_status
std::cv_status as a return status for a condition variable has two possible return codes:
https://riptutorial.com/ 745
Chapter 128: Threading
Syntax
• thread()
• thread(thread&& other)
• explicit thread(Function&& func, Args&&... args)
Parameters
Parameter Details
other Takes ownership of other, other doesn't own the thread anymore
Remarks
Some notes:
Examples
Thread operations
Often, at some point, you need to (possibly - the thread may already be done) wait for the thread
to finish, because you want to use the result for example.
int n;
std::thread thread{ calculateSomething, std::ref(n) };
//Now 'n' has the result of the calculation done in the seperate thread
std::cout << n << '\n';
https://riptutorial.com/ 746
You can also detach the thread, letting it execute freely:
//The thread will terminate when it is done, or when the main thread returns
You cannot pass a reference (or const reference) directly to a thread because std::thread will
copy/move them. Instead, use std::reference_wrapper:
void foo(int& b)
{
b = 10;
}
int a = 1;
std::thread thread{ foo, std::ref(a) }; //'a' is now really passed as reference
thread.join();
std::cout << a << '\n'; //Outputs 10
ComplexObject object;
std::thread thread{ bar, std::cref(object) }; //'object' is passed as const&
thread.join();
std::cout << object.getResult() << '\n'; //Outputs the result
Creating a std::thread
In C++, threads are created using the std::thread class. A thread is a separate flow of execution; it
is analogous to having a helper perform one task while you simultaneously perform another. When
all the code in the thread is executed, it terminates. When creating a thread, you need to pass
something to be executed on it. A few things that you can pass to a thread:
• Free functions
• Member functions
• Functor objects
• Lambda expressions
#include <iostream>
https://riptutorial.com/ 747
#include <thread>
void foo(int a)
{
std::cout << a << '\n';
}
int main()
{
// Create and execute the thread
std::thread thread(foo, 10); // foo is the function to execute, 10 is the
// argument to pass to it
return 0;
}
Member function example - executes a member function on a separate thread (Live Example):
#include <iostream>
#include <thread>
class Bar
{
public:
void foo(int a)
{
std::cout << a << '\n';
}
};
int main()
{
Bar bar;
return 0;
}
#include <iostream>
#include <thread>
class Bar
{
https://riptutorial.com/ 748
public:
void operator()(int a)
{
std::cout << a << '\n';
}
};
int main()
{
Bar bar;
return 0;
}
#include <iostream>
#include <thread>
int main()
{
auto lambda = [](int a) { std::cout << a << '\n'; };
return 0;
}
std::this_thread is a namespace which has functions to do interesting things on the current thread
from function it is called from.
Function Description
https://riptutorial.com/ 749
Function Description
void foo()
{
//Print this threads id
std::cout << std::this_thread::get_id() << '\n';
}
foo(); //The id of the main thread is printed, should be something like 2420
void foo()
{
std::this_thread::sleep_for(std::chrono::seconds(3));
}
void foo()
{
std::this_thread::sleep_until(std::chrono::system_clock::now() + std::chrono::hours(3));
}
std::cout << "We are now located 3 hours after the thread has been called\n";
void foo(int a)
{
for (int i = 0; i < al ++i)
std::this_thread::yield(); //Now other threads take priority, because this thread
//isn't doing anything important
https://riptutorial.com/ 750
thread.join();
std::async is also able to make threads. Compared to std::thread it is considered less powerful but
easier to use when you just want to run a function asynchronously.
#include <future>
#include <iostream>
int main() {
auto f = std::async(std::launch::async, square, 8);
std::cout << "square currently running\n"; //do something while square is running
std::cout << "result is " << f.get() << '\n'; //getting the result from square
}
Common Pitfalls
• std::async returns a std::future that holds the return value that will be calculated by the
function. When that future gets destroyed it waits until the thread completes, making your
code effectively single threaded. This is easily overlooked when you don't need the return
value:
• std::async works without a launch policy, so std::async(square, 5); compiles. When you do
that the system gets to decide if it wants to create a thread or not. The idea was that the
system chooses to make a thread unless it is already running more threads than it can run
efficiently. Unfortunately implementations commonly just choose not to create a thread in
that situation, ever, so you need to override that behavior with std::launch::async which
forces the system to create a thread.
When the destructor for std::thread is invoked, a call to either join() or detach() must have been
made. If a thread has not been joined or detached, then by default std::terminate will be called.
Using RAII, this is generally simple enough to accomplish:
https://riptutorial.com/ 751
class thread_joiner
{
public:
thread_joiner(std::thread t)
: t_(std::move(t))
{ }
~thread_joiner()
{
if(t_.joinable()) {
t_.join();
}
}
private:
std::thread t_;
}
void perform_work()
{
// Perform some work
}
void t()
{
thread_joiner j{std::thread(perform_work)};
// Do some other calculations while thread is running
} // Thread is automatically joined here
This also provides exception safety; if we had created our thread normally and the work done in
t() performing other calculations had thrown an exception, join() would never have been called
on our thread and our process would have been terminated.
We can create empty thread objects and assign work to them later.
If we assign a thread object to another active, joinable thread, std::terminate will automatically be
called before the thread is replaced.
#include <thread>
void foo()
{
std::this_thread::sleep_for(std::chrono::seconds(3));
}
//create 100 thread objects that do nothing
std::thread executors[100];
// Some code
https://riptutorial.com/ 752
for (int i = 0;i < 100;i++)
{
// If this object doesn't have a thread assigned
if (!executors[i].joinable())
executors[i] = std::thread(foo);
}
Basic Synchronization
std::mutex m;
void worker() {
std::lock_guard<std::mutex> guard(m); // Acquires a lock on the mutex
// Synchronized code here
} // the mutex is automatically released when guard goes out of scope
With std::lock_guard the mutex is locked for the whole lifetime of the lock object. In cases where
you need to manually control the regions for locking, use std::unique_lock instead:
std::mutex m;
void worker() {
// by default, constructing a unique_lock from a mutex will lock the mutex
// by passing the std::defer_lock as a second argument, we
// can construct the guard in an unlocked state instead and
// manually lock later.
std::unique_lock<std::mutex> guard(m, std::defer_lock);
// the mutex is not locked yet!
guard.lock();
// critical section
guard.unlock();
// mutex is again released
}
#include <condition_variable>
https://riptutorial.com/ 753
#include <cstddef>
#include <iostream>
#include <mutex>
#include <queue>
#include <random>
#include <thread>
int main()
{
std::condition_variable cond;
std::mutex mtx;
std::queue<int> intq;
bool stopped = false;
std::thread producer{[&]()
{
// Prepare a random number generator.
// Our producer will simply push random numbers to intq.
//
std::default_random_engine gen{};
std::uniform_int_distribution<int> dist{};
// All done.
// Acquire the lock, set the stopped flag,
// then inform the consumer.
std::lock_guard<std::mutex> L{mtx};
stopped = true;
cond.notify_one();
}};
std::thread consumer{[&]()
{
do{
std::unique_lock<std::mutex> L{mtx};
cond.wait(L,[&]()
{
// Acquire the lock only if
// we've stopped or the queue
// isn't empty
return stopped || ! intq.empty();
});
https://riptutorial.com/ 754
// We own the mutex here; pop the queue
// until it empties out.
while( ! intq.empty())
{
const auto val = intq.front();
intq.pop();
if(stopped){
// producer has signaled a stop
std::cout << "Consumer is done!" << std::endl;
break;
}
}while(true);
}};
consumer.join();
producer.join();
return 0;
}
C++11 threading primitives are still relatively low level. They can be used to write a higher level
construct, like a thread pool:
C++14
struct tasks {
// the mutex, condition variable and deque form a single
// thread-safe triggered queue of tasks:
std::mutex m;
std::condition_variable v;
// note that a packaged_task<void> can store a packaged_task<R>:
std::deque<std::packaged_task<void()>> work;
// queue( lambda ) will enqueue the lambda into the tasks for the threads
// to use. A future of the type the lambda returns is given to let you get
// the result out.
template<class F, class R=std::result_of_t<F&()>>
std::future<R> queue(F&& f) {
// wrap the function object into a packaged task, splitting
// execution from the return value:
std::packaged_task<R()> p(std::forward<F>(f));
auto r=p.get_future(); // get the return value before we hand off the task
{
std::unique_lock<std::mutex> l(m);
work.emplace_back(std::move(p)); // store the task<R()> as a task<void()>
https://riptutorial.com/ 755
}
v.notify_one(); // wake a thread to work on the task
https://riptutorial.com/ 756
// otherwise, run the task:
f();
}
}
};
tasks.queue( []{ return "hello world"s; } ) returns a std::future<std::string>, which when the
tasks object gets around to running it is populated with hello world.
Live example.
C++11
More on Mutexes.
Thread-local storage
Thread-local storage can be created using the thread_local keyword. A variable declared with the
thread_local specifier is said to have thread storage duration.
• Each thread in a program has its own copy of each thread-local variable.
• A thread-local variable with function (local) scope will be initialized the first time control
passes through its definition. Such a variable is implicitly static, unless declared extern.
• A thread-local variable with namespace or class (non-local) scope will be initialized as part of
thread startup.
• Thread-local variables are destroyed upon thread termination.
• A member of a class can only be thread-local if it is static. There will therefore be one copy
of that variable per thread, rather than one copy per (thread, instance) pair.
Example:
void debug_counter() {
thread_local int count = 0;
Logger::log("This function has been called %d times by this thread", ++count);
}
https://riptutorial.com/ 757
Chapter 129: Trailing return type
Syntax
• function_name ( [function_args] ) [function_attributes] [function_qualifiers] -> trailing-return-
type [requires_clause]
Remarks
The above syntax shows a full function declaration using a trailing type, where square brackets
indicate an optional part of the function declaration (like the argument list if a no-arg function).
Additionally, the syntax of the trailing return type prohibits defining a class, union, or enum type
inside a trailing return type (note that this is not allowed in a leading return type either). Other than
that, types can be spelled the same way after the -> as they would be elsewhere.
Examples
Avoid qualifying a nested type name
class ClassWithAReallyLongName {
public:
class Iterator { /* ... */ };
Iterator end();
};
The trailing return type is looked up in the scope of the class, while a leading return type is looked
up in the enclosing namespace scope and can therefore require "redundant" qualification.
Lambda expressions
A lambda can only have a trailing return type; the leading return type syntax is not applicable to
lambdas. Note that in many cases it is not necessary to specify a return type for a lambda at all.
https://riptutorial.com/ 758
auto lambda = [](bool b) -> Base* { if (b) return new Derived1; else return new Derived2; };
// ill-formed: auto lambda = Base* [](bool b) { ... };
https://riptutorial.com/ 759
Chapter 130: type deduction
Remarks
In November 2014, the C++ Standardization Committee adopted proposal N3922, which
eliminates the special type deduction rule for auto and braced initializers using direct initialization
syntax. This is not part of the C++ standard but has been implemented by some compilers.
Examples
Template parameter deduction for constructors
Prior to C++17, template deduction cannot deduce the class type for you in a constructor. It must
be explicitly specified. Sometimes, however, these types can be very cumbersome or (in the case
of lambdas) impossible to name, so we got a proliferation of type factories (like make_pair(),
make_tuple(), back_inserter(), etc.).
C++17
Constructors are considered to deduce the class template parameters, but in some cases this is
insufficient and we can provide explicit deduction guides:
template<typename T>
void f(ParamType param);
f(expr);
Case 1: ParamType is a Reference or Pointer, but not a Universal or Forward Reference. In this
case type deduction works this way. The compiler ignores the reference part if it exists in expr. The
https://riptutorial.com/ 760
compiler then pattern-matches expr's type against ParamType to determing T.
template<typename T>
void f(T& param); //param is a reference
Case 2: ParamType is a Universal Reference or Forward Reference. In this case type deduction is
the same as in case 1 if the expr is an rvalue. If expr is an lvalue, both T and ParamType are deduced
to be lvalue references.
template<typename T>
void f(T&& param); // param is a universal reference
Case 3: ParamType is Neither a Pointer nor a Reference. If expr is a reference the reference part is
ignored. If expr is const that is ignored as well. If it is volatile that is also ignored when deducing
T's type.
template<typename T>
void f(T param); // param is now passed by value
C++11
Type deduction using the auto keyword works almost the same as Template Type Deduction.
Below are a few examples:
https://riptutorial.com/ 761
const int
As you can see if you use braced initializers, auto is forced into creating a variable of type
std::initializer_list<T>. If it can't deduce the of T, the code is rejected.
When auto is used as the return type of a function, it specifies that the function has a trailing return
type.
C++14
C++14 allows, in addition to the usages of auto allowed in C++11, the following:
1. When used as the return type of a function without a trailing return type, specifies that the
function's return type should be deduced from the return statements in the function's body, if
any.
// f returns int:
auto f() { return 42; }
// g returns void:
auto g() { std::cout << "hello, world!\n"; }
2. When used in the parameter type of a lambda, defines the lambda to be a generic lambda.
The special form decltype(auto) deduces a type using the type deduction rules of decltype rather
than those of auto.
In C++03 and earlier, the auto keyword had a completely different meaning as a storage class
https://riptutorial.com/ 762
specifier that was inherited from C.
https://riptutorial.com/ 763
Chapter 131: Type Erasure
Introduction
Type erasure is a set of techniques for creating a type that can provide a uniform interface to
various underlying types, while hiding the underlying type information from the client.
std::function<R(A...)>, which has the ability to hold callable objects of various types, is perhaps
the best known example of type erasure in C++.
Examples
Basic mechanism
Type erasure is a way to hide the type of an object from code using it, even though it is not derived
from a common base class. In doing so, it provides a bridge between the worlds of static
polymorphism (templates; at the place of use, the exact type must be known at compile time, but it
need not be declared to conform to an interface at definition) and dynamic polymorphism
(inheritance and virtual functions; at the place of use, the exact type need not be known at compile
time, but must be declared to conform to an interface at definition).
#include <ostream>
class Printable
{
public:
template <typename T>
Printable(T value) : pValue(new Value<T>(value)) {}
~Printable() { delete pValue; }
void print(std::ostream &os) const { pValue->print(os); }
private:
Printable(Printable const &) /* in C++1x: =delete */; // not implemented
void operator = (Printable const &) /* in C++1x: =delete */; // not implemented
struct ValueBase
{
virtual ~ValueBase() = default;
virtual void print(std::ostream &) const = 0;
};
template <typename T>
struct Value : ValueBase
{
Value(T const &t) : v(t) {}
virtual void print(std::ostream &os) const { os << v; }
T v;
};
ValueBase *pValue;
};
At the use site, only the above definition need to be visible, just as with base classes with virtual
https://riptutorial.com/ 764
functions. For example:
#include <iostream>
Note that this is not a template, but a normal function that only needs to be declared in a header
file, and can be defined in an implementation file (unlike templates, whose definition must be
visible at the place of use).
At the definition of the concrete type, nothing needs to be known about Printable, it just needs to
conform to an interface, as with templates:
We can now pass an object of this class to the function defined above:
MyType foo = { 42 };
print_value(foo);
A Regular type is a type that can be constructed and assigned-to and assigned-from via copy or
move, can be destroyed, and can be compared equal-to. It can also be constructed from no
arguments. Finally, it also has support for a few other operations that are highly useful in various
std algorithms and containers.
This is the root paper, but in C++11 would want to add std::hash support.
https://riptutorial.com/ 765
std::type_info const&(*type)(); // typeid(T)
dtor_unique_ptr(*clone)(void const* self); // T(T const&)
};
template<class T>
regular_vtable make_regular_vtable() noexcept {
return {
[](void* dest, void const* src){ *static_cast<T*>(dest) = *static_cast<T const*>(src); },
[](void* dest, void* src){ *static_cast<T*>(dest) = std::move(*static_cast<T*>(src)); },
[](void const* lhs, void const* rhs){ return *static_cast<T const*>(lhs) == *static_cast<T
const*>(rhs); },
[](void const* lhs, void const* rhs) { return std::less<T>{}(*static_cast<T
const*>(lhs),*static_cast<T const*>(rhs)); },
[](void const* self){ return std::hash<T>{}(*static_cast<T const*>(self)); },
[]()->decltype(auto){ return typeid(T); },
[](void const* self){ return make_dtor_unique_ptr<T>(*static_cast<T const*>(self)); }
};
}
template<class T>
regular_vtable const* get_regular_vtable() noexcept {
static const regular_vtable vtable=make_regular_vtable<T>();
return &vtable;
}
struct regular_type {
using self=regular_type;
regular_vtable const* vtable = 0;
dtor_unique_ptr ptr{nullptr, [](void*){}};
template<class T, class...Args>
void emplace( Args&&... args ) {
ptr = make_dtor_unique_ptr<T>(std::forward<Args>(args)...);
if (ptr)
vtable = get_regular_vtable<T>();
else
vtable = nullptr;
}
friend bool operator==(regular_type const& lhs, regular_type const& rhs) {
if (lhs.vtable != rhs.vtable) return false;
return lhs.vtable->equals( lhs.ptr.get(), rhs.ptr.get() );
}
bool before(regular_type const& rhs) const {
auto const& lhs = *this;
if (!lhs.vtable || !rhs.vtable)
return std::less<regular_vtable const*>{}(lhs.vtable,rhs.vtable);
if (lhs.vtable != rhs.vtable)
return lhs.vtable->type().before(rhs.vtable->type());
return lhs.vtable->order( lhs.ptr.get(), rhs.ptr.get() );
}
// technically friend bool operator< that calls before is also required
https://riptutorial.com/ 766
o.vtable = nullptr;
}
friend void swap(regular_type& lhs, regular_type& rhs){
std::swap(lhs.ptr, rhs.ptr);
std::swap(lhs.vtable, rhs.vtable);
}
regular_type& operator=(regular_type&& o) {
if (o.vtable == vtable) {
vtable->move_assign(ptr.get(), o.ptr.get());
return *this;
}
auto tmp = std::move(o);
swap(*this, tmp);
return *this;
}
regular_type(regular_type const& o):
vtable(o.vtable),
ptr(o.vtable?o.vtable->clone(o.ptr.get()):dtor_unique_ptr{nullptr, [](void*){}})
{
if (!ptr && vtable) vtable = nullptr;
}
regular_type& operator=(regular_type const& o) {
if (o.vtable == vtable) {
vtable->copy_assign(ptr.get(), o.ptr.get());
return *this;
}
auto tmp = o;
swap(*this, tmp);
return *this;
}
std::size_t hash() const {
if (!vtable) return 0;
return vtable->hash(ptr.get());
}
template<class T,
std::enable_if_t< !std::is_same<std::decay_t<T>, regular_type>{}, int>* =nullptr
>
regular_type(T&& t) {
emplace<std::decay_t<T>>(std::forward<T>(t));
}
};
namespace std {
template<>
struct hash<regular_type> {
std::size_t operator()( regular_type const& r )const {
return r.hash();
}
};
template<>
struct less<regular_type> {
bool operator()( regular_type const& lhs, regular_type const& rhs ) const {
return lhs.before(rhs);
}
};
}
live example.
Such a regular type can be used as a key for a std::map or a std::unordered_map that accepts
anything regular for a key, like:
https://riptutorial.com/ 767
std::map<regular_type, std::any>
Unlike any, my regular_type does no small object optimization nor does it support getting the
original data back. Getting the original type back isn't hard.
Small object optimization requires that we store an aligned storage buffer within the regular_type,
and carefully tweak the deleter of the ptr to only destroy the object and not delete it.
I would start at make_dtor_unique_ptr and teach it how to sometimes store the data in a buffer, and
then in the heap if no room in the buffer. That may be sufficient.
A move-only `std::function`
std::functiontype erases down to a few operations. One of the things it requires is that the stored
value be copyable.
This causes problems in a few contexts, like lambdas storing unique ptrs. If you are using the
std::function in a context where copying doesn't matter, like a thread pool where you dispatch
tasks to threads, this requirement can add overhead.
Thus the task. This demonstrates how you could write a simple std::function type. I omitted the
copy constructor (which would involve adding a clone method to details::task_pimpl<...> as well).
template<class Sig>
struct task;
https://riptutorial.com/ 768
// the void version discards the return value of f:
template<class F, class...Args>
struct task_pimpl_impl<F,void,Args...>:task_pimpl<void,Args...> {
F f;
template<class Fin>
task_pimpl_impl( Fin&& fin ):f(std::forward<Fin>(fin)) {}
virtual void invoke(Args&&...args) const final override {
f(std::forward<Args>(args)...);
}
virtual const std::type_info& target_type() const final override {
return typeid(F);
}
};
};
template<class R, class...Args>
struct task<R(Args...)> {
// semi-regular:
task()=default;
task(task&&)=default;
// no copy
private:
// aliases to make some SFINAE code below less ugly:
template<class F>
using call_r = std::result_of_t<F const&(Args...)>;
template<class F>
using is_task = std::is_same<std::decay_t<F>, task>;
public:
// can be constructed from a callable F
template<class F,
// that can be invoked with Args... and converted-to-R:
class= decltype( (R)(std::declval<call_r<F>>()) ),
// and is not this same type:
std::enable_if_t<!is_task<F>{}, int>* = nullptr
>
task(F&& f):
m_pImpl( make_pimpl(std::forward<F>(f)) )
{}
https://riptutorial.com/ 769
T* target() {
return target_impl<T>();
}
template< class T >
const T* target() const {
return target_impl<T>();
}
// compare with nullptr :
friend bool operator==( std::nullptr_t, task const& self ) { return !self; }
friend bool operator==( task const& self, std::nullptr_t ) { return !self; }
friend bool operator!=( std::nullptr_t, task const& self ) { return !!self; }
friend bool operator!=( task const& self, std::nullptr_t ) { return !!self; }
private:
template<class T>
using pimpl_t = details::task_pimpl_impl<T, R, Args...>;
template<class F>
static auto make_pimpl( F&& f ) {
using dF=std::decay_t<F>;
using pImpl_t = pimpl_t<dF>;
return std::make_unique<pImpl_t>(std::forward<F>(f));
}
std::unique_ptr<details::task_pimpl<R,Args...>> m_pImpl;
To make this library-worthy, you'd want to add in a small buffer optimization, so it does not store
every callable on the heap.
Adding SBO would require a non-default task(task&&), some std::aligned_storage_t within the
class, a m_pImpl unique_ptr with a deleter that can be set to destroy-only (and not return the
memory to the heap), and a emplace_move_to( void* ) = 0 in the task_pimpl.
Not all type erasure involves virtual inheritance, allocations, placement new, or even function
pointers.
What makes type erasure type erasure is that it describes a (set of) behavior(s), and takes any
type that supports that behavior and wraps it up. All information that isn't in that set of behaviors is
"forgotten" or "erased".
An array_view takes its incoming range or container type and erases everything except the fact it is
a contiguous buffer of T.
https://riptutorial.com/ 770
template<class Src, class T>
using compatible_data = std::integral_constant<bool, std::is_same< data_t<Src>, T* >{} ||
std::is_same< data_t<Src>, std::remove_const_t<T>* >{}>;
template<class T>
struct array_view {
// the core of the class:
T* b=nullptr;
T* e=nullptr;
T* begin() const { return b; }
T* end() const { return e; }
// useful helpers that let you generate other ranges from this one
// quickly and safely:
array_view without_front( std::size_t i=1 ) const {
i = (std::min)(i, size());
return {begin()+i, end()};
}
array_view without_back( std::size_t i=1 ) const {
i = (std::min)(i, size());
return {begin(), end()-i};
}
// final constructor:
array_view(T* s, T* f):b(s),e(f) {}
// start and length is useful in my experience:
array_view(T* s, std::size_t length):array_view(s, s+length) {}
// array constructor:
template<std::size_t N>
array_view( T(&arr)[N] ):array_view(arr, N) {}
https://riptutorial.com/ 771
};
an array_view takes any container that supports .data() returning a pointer to T and a .size()
method, or an array, and erases it down to being a random-access range over contiguous Ts.
It can take a std::vector<T>, a std::string<T> a std::array<T, N> a T[37], an initializer list (including
{} based ones), or something else you make up that supports it (via T* x.data() and size_t
x.size()).
In this case, the data we can extract from the thing we are erasing, together with our "view" non-
owning state, means we don't have to allocate memory or write custom type-dependent functions.
Live example.
This example uses C++14 and boost::any. In C++17 you can swap in std::any instead.
super_any<decltype(print)> a = 7;
(a->*print)(std::cout);
This example is based off of work by @dyp and @cpplearner as well as my own.
This creates a function pointer type, and a factory for said function pointers, given an any_method:
template<class any_method>
using any_sig_from_method = typename any_method::signature;
https://riptutorial.com/ 772
{
template<class T>
using decorate = std::conditional_t< any_method::is_const, T const, T >;
any_method_function::type is the type of a function pointer we will store alongside the instance.
any_method_function::operator() takes a tag_t<T> and writes a custom instance of the
any_method_function::type that assumes the any& is going to be a T.
We want to be able to type-erase more than one method at a time. So we bundle them up in a
tuple, and write a helper wrapper to stick the tuple into static storage on a per-type basis and
maintain a pointer to them.
template<class...any_methods>
using any_method_tuple = std::tuple< typename any_method_function<any_methods>::type... >;
template<class...methods>
struct any_methods {
private:
any_method_tuple<methods...> const* vtable = 0;
template<class T>
static any_method_tuple<methods...> const* get_vtable( tag_t<T> ) {
static const auto table = make_vtable<methods...>(tag<T>);
return &table;
}
public:
any_methods() = default;
template<class T>
any_methods( tag_t<T> ): vtable(get_vtable(tag<T>)) {}
any_methods& operator=(any_methods const&)=default;
template<class T>
void change_type( tag_t<T> ={} ) { vtable = get_vtable(tag<T>); }
template<class any_method>
auto get_invoker( tag_t<any_method> ={} ) const {
return std::get<typename any_method_function<any_method>::type>( *vtable );
}
};
We could specialize this for a cases where the vtable is small (for example, 1 item), and use direct
https://riptutorial.com/ 773
pointers stored in-class in those cases for efficiency.
Now we start the super_any. I use super_any_t to make the declaration of super_any a bit easier.
template<class...methods>
struct super_any_t;
This searches the methods that the super any supports for SFINAE and better error messages:
or in C++17:
Note that using a non-lambda can make things hairy, as we use the type for a lookup step. This
can be fixed, but would make this example longer than it already is. So always initialize an any
method from a lambda, or from a type parametarized on a lambda.
https://riptutorial.com/ 774
F f;
public:
template<class Any,
// SFINAE testing that one of the Anys's matches this type:
std::enable_if_t< super_method_applies< Any&&, any_method >{}, int>* =nullptr
>
friend auto operator->*( Any&& self, any_method const& m ) {
// we don't use the value of the any_method, because each any_method has
// a unique type (!) and we check that one of the auto*'s in the super_any
// already has a pointer to us. We then dispatch to the corresponding
// any_method_data...
template<class...Args>
decltype(auto) operator()(Args&&...args)const {
return f(std::forward<Args>(args)...);
}
};
This is the augmented any. It is both an any, and it carries around a bundle of type-erasure function
pointers that change whenever the contained any does:
template<class... methods>
struct super_any_t:boost::any, any_methods<methods...> {
using vtable=any_methods<methods...>;
public:
template<class T,
std::enable_if_t< !std::is_base_of<super_any_t, std::decay_t<T>>{}, int> =0
>
super_any_t( T&& t ):
boost::any( std::forward<T>(t) )
{
using dT=std::decay_t<T>;
this->change_type( tag<dT> );
}
https://riptutorial.com/ 775
vtable(o)
{}
super_any_t(super_any_t const& o):
boost::any( o.as_any() ),
vtable(o)
{}
template<class S,
std::enable_if_t< std::is_same<std::decay_t<S>, super_any_t>{}, int> =0
>
super_any_t( S&& o ):
boost::any( std::forward<S>(o).as_any() ),
vtable(o)
{}
super_any_t& operator=(super_any_t&&)=default;
super_any_t& operator=(super_any_t const&)=default;
template<class T,
std::enable_if_t< !std::is_same<std::decay_t<T>, super_any_t>{}, int>* =nullptr
>
super_any_t& operator=( T&& t ) {
((boost::any&)*this) = std::forward<T>(t);
using dT=std::decay_t<T>;
this->change_type( tag<dT> );
return *this;
}
};
Because we store the any_methods as const objects, this makes making a super_any a bit easier:
template<class...Ts>
using super_any = super_any_t< std::remove_cv_t<Ts>... >;
Test code:
int main()
{
super_any<decltype(print), decltype(wprint)> a = 7;
super_any<decltype(print), decltype(wprint)> a2 = 7;
(a->*print)(std::cout);
(a->*wprint)(std::wcout);
}
live example.
Originally posted here in a SO self question & answer (and people noted above helped with the
implementation).
https://riptutorial.com/ 776
Chapter 132: Type Inference
Introduction
This topic discusses about type inferencing that involves the keyword auto type that is available
from C++11.
Remarks
It is usually better to declare const, & and constexpr whenever you use auto if it is ever required to
prevent unwanted behaviors such as copying or mutations. Those additional hints ensures that the
compiler does not generate any other forms of inference. It is also not advisible to over use auto
and should be used only when the actual declaration is very long, especially with STL templates.
Examples
Data Type: Auto
This example shows the basic type inferences the compiler can perform.
auto a = 1; // a = int
auto b = 2u; // b = unsigned int
auto c = &a; // c = int*
const auto d = c; // d = const int*
const auto& e = b; // e = const unsigned int&
However, the auto keyword does not always perform the expected type inference without
additional hints for & or const or constexpr
// y = unsigned int,
// note that y does not infer as const unsigned int&
// The compiler would have generated a copy instead of a reference value to e or b
auto y = e;
Lambda auto
The data type auto keyword is a convenient way for programmers to declare lambda functions. It
helps by shortening the amount of text programmers need to type to declare a function pointer.
https://riptutorial.com/ 777
auto c = Dothis(1, 2); // c = int
auto d = pDothis(1, 2); // d = int
By default, if the return type of lambda functions is not defined, it will be automatically inferred from
the return expression types.
This example shows how auto can be used to shorten type declaration for for loops
https://riptutorial.com/ 778
Chapter 133: Type Keywords
Examples
class
class foo {
int x;
public:
int get_x();
void set_x(int new_x);
};
2. Introduces an elaborated type specifier, which specifies that the following name is the name
of a class type. If the class name has been declared already, it can be found even if hidden
by another name. If the class name has not been declared already, it is forward-declared.
4. In the declaration of a template template parameter, the keyword class precedes the name
of the parameter. Since the argument for a template template parameter can only be a class
template, the use of class here is redundant. However, the grammar of C++ requires it.
https://riptutorial.com/ 779
U<double>::do_it();
}
5. Note that sense 2 and sense 3 may be combined in the same declaration. For example:
foo<class bar> x; // <- bar does not have to have previously appeared.
C++11
struct
• If a class type is defined using the keyword struct, then the default accessibility of bases and
members is public rather than private.
• struct cannot be used to declare a template type parameter or template template parameter;
only class can.
enum
enum Direction {
UP,
LEFT,
DOWN,
RIGHT
};
Direction d = UP;
C++11
In C++11, enum may optionally be followed by class or struct to define a scoped enum.
Furthermore, both scoped and unscoped enums can have their underlying type explicitly specified
by : T following the enum name, where T refers to an integer type.
https://riptutorial.com/ 780
PDF,
OTHER
};
Format f = Format::TEXT;
Enumerators in normal enums may also be preceded by the scope operator, although they are still
considered to be in the scope the enum was defined in.
l1 = ENGLISH;
l2 = Language::OTHER;
2. Introduces an elaborated type specifier, which specifies that the following name is the name
of a previously declared enum type. (An elaborated type specifier cannot be used to forward-
declare an enum type.) An enum can be named in this way even if hidden by another name.
C++11
3. Introduces an opaque enum declaration, which declares an enum without defining it. It can
either redeclare a previously declared enum, or forward-declare an enum that has not been
previously declared.
An enum first declared as scoped cannot later be declared as unscoped, or vice versa. All
declarations of an enum must agree in underlying type.
When forward-declaring an unscoped enum, the underlying type must be explicitly specified,
since it cannot be inferred until the values of the enumerators are known.
union
https://riptutorial.com/ 781
1. Introduces the definition of a union type.
2. Introduces an elaborated type specifier, which specifies that the following name is the name
of a union type. If the union name has been declared already, it can be found even if hidden
by another name. If the union name has not been declared already, it is forward-declared.
https://riptutorial.com/ 782
Chapter 134: Type Traits
Remarks
Type traits are templated constructs used to compare and test the properties of different types at
compile time. They can be used to provide conditional logic at compile time that can limit or extend
the functionality of your code in a specific manner. The type traits library was brought in with the
c++11 standard which provides a number different functionalities. It is also possible to create your
own type trait comparison templates.
Examples
Standard type traits
C++11
The type_traits header contains a set of template classes and helpers to transform and check
properties of types at compile-time.
These traits are typically used in templates to check for user errors, support generic programming,
and allow for optimizations.
Most type traits are used to check if a type fulfils some criteria. These have the following form:
If the template class is instantiated with a type which fulfils some criteria foo, then is_foo<T>
inherits from std::integral_constant<bool,true> (a.k.a. std::true_type), otherwise it inherits from
std::integral_constant<bool,false> (a.k.a. std::false_type). This gives the trait the following
members:
Constants
static constexpr bool value
Functions
operator bool
Returns value
C++14
https://riptutorial.com/ 783
bool operator()
Returns value
Types
Name Definition
value_type bool
type std::integral_constant<bool,value>
The trait can then be used in constructs such as static_assert or std::enable_if. An example with
std::is_pointer:
There are also various traits which transform types, such as std::add_pointer and
std::underlying_type. These traits generally expose a single type member type which contains the
transformed type. For example, std::add_pointer<int>::type is int*.
C++11
The std::is_same<T, T> type relation is used to compare two types. It will evaluate as boolean, true
if the types are the same and false if otherwise.
e.g.
https://riptutorial.com/ 784
// Prints false on all compilers.
std::cout << std::is_same<unsigned int, int>::value << "\n";
The std::is_same type relation will also work regardless of typedefs. This is actually demonstrated
in the first example when comparing int == int32_t however this is not entirely clear.
e.g.
When combined with a static assert the std::is_same template can be valuable tool in enforcing
proper usage of templated classes and functions.
e.g. A function that only allows input from an int and a choice of two structs.
#include <type_traits>
struct foo {
int member;
// Other variables
};
struct bar {
char member;
};
template<typename T>
int AddStructMember(T var1, int var2) {
// If type T != foo || T != bar then show error message.
static_assert(std::is_same<T, foo>::value ||
std::is_same<T, bar>::value,
"This function does not support the specified type.");
return var1.member + var2;
}
C++11
There are a number of different type traits that compare more general types.
Is Integral:
Evaluates as true for all integer types int, char, long, unsigned int etc.
https://riptutorial.com/ 785
Is Floating Point:
Evaluates as true for all floating point types. float,double, long double etc.
Is Enum:
Is Pointer:
Is Class:
Evaluates as true for all classes and struct, with the exception of enum class.
Type Properties
C++11
Type properties compare the modifiers that can be placed upon different variables. The usefulness
of these type traits is not always obvious.
Note: The example below would only offer an improvement on a non-optimizing compiler. It is a
simple a proof of concept, rather than complex example.
https://riptutorial.com/ 786
e.g. Fast divide by four.
template<typename T>
inline T FastDivideByFour(cont T &var) {
// Will give an error if the inputted type is not an unsigned integral type.
static_assert(std::is_unsigned<T>::value && std::is_integral<T>::value,
"This function is only designed for unsigned integral types.");
return (var >> 2);
}
Is Constant:
Is Volatile:
Is signed:
Is Unsigned:
https://riptutorial.com/ 787
Chapter 135: Typedef and type aliases
Introduction
The typedef and (since C++11) using keywords can be used to give a new name to an existing
type.
Syntax
• typedef type-specifier-seq init-declarator-list;
• attribute-specifier-seq typedef decl-specifier-seq init-declarator-list; // since C++11
• using identifier attribute-specifier-seq(opt) = type-id; // since C++11
Examples
Basic typedef syntax
A typedef declaration has the same syntax as a variable or function declaration, but it contains the
word typedef. The presence of typedef causes the declaration to declare a type instead of a
variable or function.
Once a type alias has been defined, it can be used interchangeably with the original name of the
type.
typedef never creates a distinct type. It only gives another way of referring to an existing type.
struct S {
int f(int);
};
typedef int I;
// ok: defines int S::f(int)
I S::f(I x) { return x; }
https://riptutorial.com/ 788
The rule that typedef declarations have the same syntax as ordinary variable and function
declarations can be used to read and write more complex declarations.
This is especially useful for constructs with confusing syntax, such as pointers to non-static
members.
void (Foo::*pmf)(int); // pmf has type "pointer to member function of Foo taking int
// and returning void"
typedef void (Foo::*pmf)(int); // pmf is an alias for "pointer to member function of Foo
// taking int and returning void"
It is hard to remember the syntax of the following function declarations, even for experienced
programmers:
The typedef keyword is a specifier, so it applies separately to each declarator. Therefore, each
name declared refers to the type that that name would have in the absence of typedef.
int *x, (*p)(); // x has type int*, and p has type int(*)()
typedef int *x, (*p)(); // x is an alias for int*, while p is an alias for int(*)()
C++11
The syntax of using is very simple: the name to be defined goes on the left hand side, and the
definition goes on the right hand side. No need to scan to see where the name is.
using I = int;
using A = int[100]; // array of 100 ints
using FP = void(*)(int); // pointer to function of int returning void
using MP = void (Foo::*)(int); // pointer to member function of Foo of int returning void
Creating a type alias with using has exactly the same effect as creating a type alias with typedef. It
https://riptutorial.com/ 789
is simply an alternative syntax for accomplishing the same thing.
Unlike typedef, using can be templated. A "template typedef" created with using is called an alias
template.
https://riptutorial.com/ 790
Chapter 136: Undefined Behavior
Introduction
What is undefined behavior (UB)? According to the ISO C++ Standard (§1.3.24, N4296), it is
"behavior for which this International Standard imposes no requirements."
This means that when a program encounters UB, it is allowed to do whatever it wants. This often
means a crash, but it may simply do nothing, make demons fly out of your nose, or even appear to
work properly!
Needless to say, you should avoid writing code that invokes UB.
Remarks
If a program contains undefined behavior, the C++ standard places no constraints on its behavior.
• It may appear to work as the developer intended, but it may also crash or produce strange
results.
• The behavior may vary between runs of the same program.
• Any part of the program may malfunction, including lines that come before the line that
contains undefined behavior.
• The implementation is not required to document the result of undefined behavior.
An implementation may document the result of an operation that produces undefined behavior
according to the standard, but a program that depends on such documented behavior is not
portable.
Intuitively, undefined behavior is considered a bad thing as such errors can't be handled
graciously through, say, exception handlers.
But leaving some behavior undefined is actually an integral part of C++'s promise "you don't pay
for what you don't use". Undefined behavior allows a compiler to assume the developer knows
what he's doing and not introduce code to check for the mistakes highlighted in the above
examples.
• Most compilers have warning flags to warn about some cases of undefined behavior at
compile time.
• Newer versions of gcc and clang include a so-called "Undefined Behavior Sanitizer" flag (-
fsanitize=undefined) that will check for undefined behavior at runtime, at a performance cost.
• lint-like tools may perform more thorough undefined behavior analysis.
https://riptutorial.com/ 791
Undefined, unspecified and implementation-defined behavior
2. Certain aspects and operations of the abstract machine are described in this
International Standard as implementation-defined (for example, sizeof(int)).
These constitute the parameters of the abstract machine. Each implementation
shall include documentation describing its characteristics and behavior in these
respects. [CUT]
3. Certain other aspects and operations of the abstract machine are described in
this International Standard as unspecified (for example, evaluation of
expressions in a new-initializer if the allocation function fails to allocate memory).
Where possible, this International Standard defines a set of allowable behaviors.
These define the nondeterministic aspects of the abstract machine. An instance
of the abstract machine can thus have more than one possible execution for a
given program and a given input.
Examples
Reading or writing through a null pointer
This is undefined behavior, because a null pointer does not point to any valid object, so there is
no object at *ptr to write to.
Although this most often causes a segmentation fault, it is undefined and anything can happen.
Omitting the return statement in a function which is has a return type that is not void is undefined
behavior.
int function() {
// Missing return statement
}
int main() {
function(); //Undefined Behavior
https://riptutorial.com/ 792
}
Most modern day compilers emit a warning at compile time for this kind of undefined behavior.
Note: main is the only exception to the rule. If main doesn't have a return statement, the compiler
automatically inserts return 0; for you, so it can be safely left out.
C++11
The initialisation of str in the above example was formally deprecated (scheduled for removal from
a future version of the standard) in C++03. A number of compilers before 2003 might issue a
warning about this (e.g. a suspicious conversion). After 2003, compilers typically warn about a
deprecated conversion.
C++11
The above example is illegal, and results in a compiler diagnostic, in C++11 and later. A similar
example may be constructed to exhibit undefined behaviour by explicitly permitting the type
conversion, such as:
It is undefined behavior to access an index that is out of bounds for an array (or standard library
container for that matter, as they are all implemented using a raw array):
It is allowed to have a pointer pointing to the end of the array (in this case array + 5), you just can't
dereference it, as it is not a valid element.
const int *end = array + 5; // Pointer to one past the last index
for (int *p = array; p != end; ++p)
// Do something with `p`
In general, you're not allowed to create an out-of-bounds pointer. A pointer must point to an
element within the array, or one past the end.
https://riptutorial.com/ 793
Integer division by zero
Division by 0 is mathematically undefined, and as such it makes sense that this is undefined
behavior.
However:
Most implementation implement IEEE-754, which defines floating point division by zero to return
NaN (if numerator is 0.0f), infinity (if numerator is positive) or -infinity (if numerator is negative).
int x = INT_MAX + 1;
If during the evaluation of an expression, the result is not mathematically defined or not
in the range of representable values for its type, the behavior is undefined.
(C++11 Standard paragraph 5/4)
This is one of the more nasty ones, as it usually yields reproducible, non-crashing behavior so
developers may be tempted to rely heavily on the observed behavior.
// x is 0
Unsigned integers, declared unsigned, shall obey the laws of arithmetic modulo 2^n
where n is the number of bits in the value representation of that particular size of
integer.
(C++11 Standard paragraph 3.9.1/4)
signed int x ;
if(x > x + 1)
{
//do something
}
https://riptutorial.com/ 794
Here since a signed integer overflow is not defined, compiler is free to assume that it may never
happen and hence it can optimize away the "if" block
int a;
std::cout << a; // Undefined behavior!
It is often, incorrectly, claimed that this is because the value is "indeterminate", or "whatever value
was in that memory location before". However, it is the act of accessing the value of a in the above
example that gives undefined behaviour. In practice, printing a "garbage value" is a common
symptom in this case, but that is only one possible form of undefined behaviour.
Although highly unlikely in practice (since it is reliant on specific hardware support) the compiler
could equally well electrocute the programmer when compiling the code sample above. With such
a compiler and hardware support, such a response to undefined behaviour would markedly
increase average (living) programmer understanding of the true meaning of undefined behaviour -
which is that the standard places no constraint on the resultant behaviour.
C++14
Using an indeterminate value of unsigned char type does not produce undefined behavior if the
value is used as:
or if the value is discarded. In such cases, the indeterminate value simply propagates to the result
of the expression, if applicable.
static int a;
std::cout << a; // Defined behavior, 'a' is 0
If a class, enum, inline function, template, or member of a template has external linkage and is
defined in multiple translation units, all definitions must be identical or the behavior is undefined
according to the One Definition Rule (ODR).
foo.h:
https://riptutorial.com/ 795
class Foo {
public:
double x;
private:
int y;
};
Foo get_foo();
foo.cpp:
#include "foo.h"
Foo get_foo() { /* implementation */ }
main.cpp:
// I want access to the private member, so I am going to replace Foo with my own type
class Foo {
public:
double x;
int y;
};
Foo get_foo(); // declare this function ourselves since we aren't including foo.h
int main() {
Foo foo = get_foo();
// do something with foo.y
}
The above program exhibits undefined behavior because it contains two definitions of the class
::Foo, which has external linkage, in different translation units, but the two definitions are not
identical. Unlike redefinition of a class within the same translation unit, this problem is not required
to be diagnosed by the compiler.
An object can only be deallocated by delete if it was allocated by new and is not an array. If the
argument to delete was not returned by new or is an array, the behavior is undefined.
An object can only be deallocated by delete[] if it was allocated by new and is an array. If the
argument to delete[] was not returned by new or is not an array, the behavior is undefined.
If the argument to free was not returned by malloc, the behavior is undefined.
int* p3 = static_cast<int*>(malloc(sizeof(int)));
https://riptutorial.com/ 796
free(p3); // correct
// delete p3; // undefined
// delete[] p3; // undefined
Such issues can be avoided by completely avoiding malloc and free in C++ programs, preferring
the standard library smart pointers over raw new and delete, and preferring std::vector and
std::string over raw new and delete[].
In most cases, it is illegal to access an object of one type as though it were a different type
(disregarding cv-qualifiers). Example:
float x = 42;
int y = reinterpret_cast<int&>(x);
• An object of class type can be accessed as though it were of a type that is a base class of
the actual class type.
• Any type can be accessed as a char or unsigned char, but the reverse is not true: a char array
cannot be accessed as though it were an arbitrary type.
• A signed integer type can be accessed as the corresponding unsigned type and vice versa.
A related rule is that if a non-static member function is called on an object that does not actually
have the same type as the defining class of the function, or a derived class, then undefined
behavior occurs. This is true even if the function does not access the object.
struct Base {
};
struct Derived : Base {
void f() {}
};
struct Unrelated {};
Unrelated u;
Derived& r1 = reinterpret_cast<Derived&>(u); // ok
r1.f(); // UB
Base b;
Derived& r2 = reinterpret_cast<Derived&>(b); // ok
r2.f(); // UB
If an arithmetic operation that yields a floating point type produces a value that is not in the range
of representable values of the result type, the behavior is undefined according to the C++
standard, but may be defined by other standards the machine might conform to, such as IEEE
754.
https://riptutorial.com/ 797
float x = 1.0;
for (int i = 0; i < 10000; i++) {
x *= 10.0; // will probably overflow eventually; undefined behavior
}
Member functions can be called from a constructor (or destructor) of an abstract class;
the effect of making a virtual call (10.3) to a pure virtual function directly or indirectly for
the object being created (or destroyed) from such a constructor (or destructor) is
undefined.
More generally, some C++ authorities, e.g. Scott Meyers, suggest never calling virtual functions
(even non-pure ones) from constructors and dstructors.
class transaction
{
public:
transaction(){ log_it(); }
virtual void log_it() const = 0;
};
sell_transaction s;
This implicitly calls the constructor of sell_transaction, which first calls the constructor of
transaction. When the constructor of transaction is called though, the object is not yet of the type
sell_transaction, but rather only of the type transaction.
Consequently, the call in transaction::transaction() to log_it, won't do what might seem to be the
intuitive thing - namely call sell_transaction::log_it.
Deleting a derived object via a pointer to a base class that doesn't have a
virtual destructor.
class base { };
https://riptutorial.com/ 798
class derived: public base { };
int main() {
base* p = new derived();
delete p; // The is undefined behavior!
}
In section [expr.delete] §5.3.5/3 the standard says that if delete is called on an object whose static
type does not have a virtual destructor:
if the static type of the object to be deleted is different from its dynamic type, the static
type shall be a base class of the dynamic type of the object to be deleted and the static
type shall have a virtual destructor or the behavior is undefined.
This is the case regardless of the question whether the derived class added any data members to
the base class.
It is illegal to access a reference to an object that has gone out of scope or been otherwise
destroyed. Such a reference is said to be dangling since it no longer refers to a valid object.
#include <iostream>
int& getX() {
int x = 42;
return x;
}
int main() {
int& r = getX();
std::cout << r << "\n";
}
In this example, the local variable x goes out of scope when getX returns. (Note that lifetime
extension cannot extend the lifetime of a local variable past the scope of the block in which it is
defined.) Therefore r is a dangling reference. This program has undefined behavior, although it
may appear to work and print 42 in some cases.
https://riptutorial.com/ 799
#include <algorithm>
namespace std
{
int foo(){}
}
Nothing in the standard forbids algorithm (or one of the headers it includes) defining the same
definition, and so this code would violate the One Definition Rule.
So, in general, this is forbidden. There are specific exceptions allowed, though. Perhaps most
usefully, it is allowed to add specializations for user defined types. So, for example, suppose your
code has
class foo
{
// Stuff
};
namespace std
{
template<>
struct hash<foo>
{
public:
size_t operator()(const foo &f) const;
};
}
the source value is outside the range of values that can be represented in the destination type, the
result is undefined behavior. Example:
double x = 1e100;
int y = x; // int probably cannot hold numbers that large, so this is UB
If static_cast is used to convert a pointer (resp. reference) to base class to a pointer (resp.
reference) to derived class, but the operand does not point (resp. refer) to an object of the derived
class type, the behavior is undefined. See Base to derived conversion.
https://riptutorial.com/ 800
Function call through mismatched function pointer type
In order to call a function through a function pointer, the function pointer's type must exactly match
the function's type. Otherwise, the behaviour is undefined. Example:
int f();
void (*p)() = reinterpret_cast<void(*)()>(f);
p(); // undefined
Any attempt to modify a const object results in undefined behavior. This applies to const variables,
members of const objects, and class members declared const. (However, a mutable member of a
const object is not const.)
A compiler will usually inline the value of a const int object, so it's possible that this code compiles
and prints 123. Compilers can also place const objects' values in read-only memory, so a
segmentation fault may occur. In any case, the behavior is undefined and the program might do
anything.
#include <iostream>
class Foo {
public:
int get_x() const { return m_x; }
void set_x(int x) { m_x = x; }
private:
Foo(int x, Foo*& this_ref): m_x(x) {
this_ref = this;
}
int m_x;
friend const Foo& getFoo();
};
void do_evil(int x) {
instance->set_x(x);
}
int main() {
https://riptutorial.com/ 801
const Foo& foo = getFoo();
do_evil(456);
std::cout << foo.get_x() << '\n';
}
In this code, getFoo creates a singleton of type const Foo and its member m_x is initialized to 123.
Then do_evil is called and the value of foo.m_x is apparently changed to 456. What went wrong?
Despite its name, do_evil does nothing particularly evil; all it does is call a setter through a Foo*.
But that pointer points to a const Foo object even though const_cast was not used. This pointer was
obtained through Foo's constructor. A const object does not become const until its initialization is
complete, so this has type Foo*, not const Foo*, within the constructor.
Therefore, undefined behavior occurs even though there are no obviously dangerous constructs in
this program.
When accessing a non-static member of an object through a pointer to member, if the object does
not actually contain the member denoted by the pointer, the behavior is undefined. (Such a pointer
to member can be obtained through static_cast.)
When static_cast is used to convert T D::* to T B::*, the member pointed to must belong to a
class that is a base class or derived class of B. Otherwise the behavior is undefined. See Derived
to base conversion for pointers to members
• Addition or subtraction of an integer, if the result does not belong to the same array object as
the pointer operand. (Here, the element one past the end is considered to still belong to the
array.)
int a[10];
int* p1 = &a[5];
int* p2 = p1 + 4; // ok; p2 points to a[9]
int* p3 = p1 + 5; // ok; p2 points to one past the end of a
https://riptutorial.com/ 802
int* p4 = p1 + 6; // UB
int* p5 = p1 - 5; // ok; p2 points to a[0]
int* p6 = p1 - 6; // UB
int* p7 = p3 - 5; // ok; p7 points to a[5]
• Subtraction of two pointers if they do not both belong to the same array object. (Again, the
element one past the end is considered to belong to the array.) The exception is that two null
pointers may be subtracted, yielding 0.
int a[10];
int b[10];
int *p1 = &a[8], *p2 = &a[3];
int d1 = p1 - p2; // yields 5
int *p3 = p1 + 2; // ok; p3 points to one past the end of a
int d2 = p3 - p2; // yields 7
int *p4 = &b[0];
int d3 = p4 - p1; // UB
• Any pointer arithmetic where either operand's pointee type does not match the dynamic type
of the object pointed to (ignoring cv-qualification). According to the standard, "[in] particular,
a pointer to a base class cannot be used for pointer arithmetic when the array contains
objects of a derived class type."
For the built-in shift operator, the right operand must be nonnegative and strictly less than the bit
width of the promoted left operand. Otherwise, the behavior is undefined.
C++11
https://riptutorial.com/ 803
Example from the Standard, [dcl.attr.noreturn]:
In this example, a destructor is explicitly invoked for an object that will later be automatically
destroyed.
struct S {
~S() { std::cout << "destroying S\n"; }
};
int main() {
S s;
s.~S();
} // UB: s destroyed a second time here
A similar issue occurs when a std::unique_ptr<T> is made to point at a T with automatic or static
storage duration.
Another way to destroy an object twice is by having two shared_ptrs both manage the object
without sharing ownership with each other.
https://riptutorial.com/ 804
X<T>* p; // OK
X<T*> a; // implicit generation of X<T> requires
// the implicit instantiation of X<T*> which requires
// the implicit instantiation of X<T**> which ...
};
https://riptutorial.com/ 805
Chapter 137: Unions
Remarks
Unions are very useful tools, but come with a few important caveats:
• It is undefined behavior, per the C++ standard, to access an element of a union that was not
the most recently modified member. Although a lot of C++ compilers permit this access in
well defined ways, these are extensions and cannot be guaranteed across compilers.
A std::variant (since C++17) is like a union, only it tells you what it currently contains (part of
its visible state is the type of the value it holds at a given moment: it enforces value access
happening only to that type).
• Implementations do not necessarily align members of different sizes to the same address.
Examples
Basic Union Features
Unions are a specialized struct within which all members occupy overlapping memory.
union U {
int a;
short b;
float c;
};
U u;
//Assigning to any union member changes the shared memory of all members
u.c = 4.f;
u.a = 5;
u.c != 4.f;
Typical Use
Unions are useful for minimizing memory usage for exclusive data, such as when implementing
mixed data types.
struct AnyType {
enum {
IS_INT,
IS_FLOAT
} type;
union Data {
https://riptutorial.com/ 806
int as_int;
float as_float;
} value;
Undefined Behavior
union U {
int a;
short b;
float c;
};
U u;
u.a = 10;
if (u.b == 10) {
// this is undefined behavior since 'a' was the last member to be
// written to. A lot of compilers will allow this and might issue a
// warning, but the result will be "as expected"; this is a compiler
// extension and cannot be guaranteed across compilers (i.e. this is
// not compliant/portable code).
}
https://riptutorial.com/ 807
Chapter 138: Unit Testing in C++
Introduction
Unit testing is a level in software testing that validates the behavior and correctness of units of
code.
In C++, "units of code" often refer to either classes, functions, or groups of either. Unit testing is
often performed using specialized "testing frameworks" or "testing libraries" that often use non-
trivial syntax or usage patterns.
This topic will review different strategies and unit testing libraries or frameworks.
Examples
Google Test
Google Test is a C++ testing framework maintained by Google. It requires building the gtest library
and linking it to your testing framework when building a test case file.
Minimal Example
// main.cpp
#include <gtest/gtest.h>
#include <iostream>
// Google Test test cases are created using a C++ preprocessor macro
// Here, a "test suite" name and a specific "test name" are provided.
TEST(module_name, test_name) {
std::cout << "Hello world!" << std::endl;
// Google Test will also provide macros for assertions.
ASSERT_EQ(1+1, 2);
}
return RUN_ALL_TESTS();
}
Catch
Catch is a header only library that allows you to use both TDD and BDD unit test style.
https://riptutorial.com/ 808
The following snippet is from the Catch documentation page at this link:
REQUIRE( v.size() == 5 );
REQUIRE( v.capacity() >= 5 );
https://riptutorial.com/ 809
Chapter 139: Unnamed types
Examples
Unnamed classes
Unlike a named class or struct, unnamed classes and structs must be instantiated where they are
defined, and cannot have constructors or destructors.
struct {
int foo;
double bar;
} foobar;
foobar.foo = 5;
foobar.bar = 4.0;
class {
int baz;
public:
int buzz;
void setBaz(int v) {
baz = v;
}
} barbar;
barbar.setBaz(15);
barbar.buzz = 2;
Anonymous members
As a non-standard extension to C++, common compilers allow the use of classes as anonymous
members.
struct Example {
struct {
int inner_b;
};
int outer_b;
//The anonymous struct's members are accessed as if members of the parent struct
Example() : inner_b(2), outer_b(4) {
inner_b = outer_b + 2;
}
};
Example ex;
//The same holds true for external code referencing the struct
ex.inner_b -= ex.outer_b;
https://riptutorial.com/ 810
As a type alias
Unnamed class types may also be used when creating type aliases, i.e. via typedef and using:
C++11
typedef struct {
float x;
float y;
} vec2d;
vec2d pt;
pt.x = 4.f;
pt.y = 3.f;
Anonymous Union
Member names of an anonymous union belong to the scope of the union declaration an must be
distinct to all other names of this scope. The example here has the same construction as example
Anonymous Members using "struct" but is standard conform.
struct Sample {
union {
int a;
int b;
};
int c;
};
int main()
{
Sample sa;
sa.a =3;
sa.b =4;
sa.c =5;
}
https://riptutorial.com/ 811
Chapter 140: Unspecified behavior
Remarks
If the behavior of a construct is unspecified, then the standard places some constraints on the
behavior, but leaves some freedom to the implementation, which is not required to document what
happens in a given situation. It contrasts with implementation-defined behavior, in which the
implementation is required to document what happens, and undefined behavior, in which anything
can happen.
Examples
Order of initialization of globals across TU
Whereas inside a Translation Unit, order of initialization of global variables is specified, order of
initialization across Translation Units is unspecified.
• foo.cpp
#include <iostream>
• bar.cpp
#include <iostream>
• main.cpp
int main() {}
foobar
or
barfoo
https://riptutorial.com/ 812
Value of an out-of-range enum
If a scoped enum is converted to an integral type that is too small to hold its value, the resulting
value is unspecified. Example:
enum class E {
X = 1,
Y = 1000,
};
// assume 1000 does not fit into a char
char c1 = static_cast<char>(E::X); // c1 is 1
char c2 = static_cast<char>(E::Y); // c2 has an unspecified value
Also, if an integer is converted to an enum and the integer's value is outside the range of the
enum's values, the resulting value is unspecified. Example:
enum Color {
RED = 1,
GREEN = 2,
BLUE = 3,
};
Color c = static_cast<Color>(4);
However, in the next example, the behavior is not unspecified, since the source value is within the
range of the enum, although it is unequal to all enumerators:
enum Scale {
ONE = 1,
TWO = 2,
FOUR = 4,
};
Scale s = static_cast<Scale>(3);
Here s will have the value 3, and be unequal to ONE, TWO, and FOUR.
If a void* value is converted to a pointer to object type, T*, but is not properly aligned for T, the
resulting pointer value is unspecified. Example:
The value of p3 is unspecified because p2 cannot point to an object of type int; its value is not a
properly aligned address.
https://riptutorial.com/ 813
The result of a reinterpret_cast from one function pointer type to another, or one function
reference type to another, is unspecified. Example:
int f();
auto fp = reinterpret_cast<int(*)(int)>(&f); // fp has unspecified value
C++03
The result of a reinterpret_cast from one object pointer type to another, or one object reference
type to another, is unspecified. Example:
int x = 42;
char* p = reinterpret_cast<char*>(&x); // p has unspecified value
If two pointers are compared using <, >, <=, or >=, the result is unspecified in the following cases:
• The pointers point into different arrays. (A non-array object is considered an array of size 1.)
int x;
int y;
const bool b1 = &x < &y; // unspecified
int a[10];
const bool b2 = &a[0] < &a[1]; // true
const bool b3 = &a[0] < &x; // unspecified
const bool b4 = (a + 9) < (a + 10); // true
// note: a+10 points past the end of the array
• The pointers point into the same object, but to members with different access control.
class A {
public:
int x;
int y;
bool f1() { return &x < &y; } // true; x comes before y
bool f2() { return &x < &z; } // unspecified
private:
int z;
};
A reference is not an object, and unlike an object, it is not guaranteed to occupy some contiguous
bytes of memory. The standard leaves it unspecified whether a reference requires any storage at
all. A number of features of the language conspire to make it impossible to portably examine any
storage the reference might occupy:
https://riptutorial.com/ 814
• If sizeof is applied to a reference, it returns the size of the referenced type, thereby giving no
information about whether the reference occupies any storage.
• Arrays of references are illegal, so it is not possible to examine the addresses of two
consecutive elements of a hypothetical reference of arrays in order to determine the size of a
reference.
• If the address of a reference is taken, the result is the address of the referent, so we cannot
get a pointer to the reference itself.
• If a class has a reference member, attempting to extract the address of that member using
offsetof yields undefined behavior since such a class is not a standard-layout class.
• If a class has a reference member, the class is no longer standard layout, so attempts to
access any data used to store the reference results in undefined or unspecified behavior.
In practice, in some cases a reference variable may be implemented similarly to a pointer variable
and hence occupy the same amount of storage as a pointer, while in other cases a reference may
occupy no space at all since it can be optimized out. For example, in:
void f() {
int x;
int& r = x;
// do something with r
}
the compiler is free to simply treat r as an alias for x and replace all occurrences of r in the rest of
the function f with x, and not allocate any storage to hold r.
If a function has multiple arguments, it is unspecified what order they are evaluated in. The
following code could print x = 1, y = 2 or x = 2, y = 1 but it is unspecified which.
C++17
However, each function argument is completely evaluated, and the calling object is guaranteed
evaluated before any function arguments are.
struct from_int {
from_int(int x) { std::cout << "from_int (" << x << ")\n"; }
};
https://riptutorial.com/ 815
int make_int(int x){ std::cout << "make_int (" << x << ")\n"; return x; }
bar
make_int(1)
from_int(1)
make_int(2)
from_int(2)
or
bar
make_int(2)
from_int(2)
make_int(1)
from_int(1)
it may not print bar after any of the make or from's, and it may not print:
bar
make_int(2)
make_int(1)
from_int(2)
from_int(1)
or similar. Prior to C++17 printing bar after make_ints was legal, as was doing both make_ints prior
to doing any from_ints.
C++11
All standard library containers are left in a valid but unspecified state after being moved from. For
example, in the following code, v2 will contain {1, 2, 3, 4} after the move, but v1 is not guaranteed
to be empty.
int main() {
https://riptutorial.com/ 816
std::vector<int> v1{1, 2, 3, 4};
std::vector<int> v2 = std::move(v1);
}
Some classes do have a precisely defined moved-from state. The most important case is that of
std::unique_ptr<T>, which is guaranteed to be null after being moved from.
https://riptutorial.com/ 817
Chapter 141: User-Defined Literals
Examples
User-defined literals with long double values
#include <iostream>
int main()
{
std::cout << "3 km = " << 3.0_km << " m\n";
std::cout << "3 mi = " << 3.0_mi << " m\n";
return 0;
}
3 km = 3000 m
3 mi = 4828.03 m
C++14
Those following duration user literals are declared in the namespace std::literals::chrono_literals,
where both literals and chrono_literals are inline namespaces. Access to these operators can be
gained with using namespace std::literals, using namespace std::chrono_literals, and using
namespace std::literals::chrono_literals.
#include <chrono>
#include <iostream>
int main()
{
using namespace std::literals::chrono_literals;
std::chrono::nanoseconds t1 = 600ns;
std::chrono::microseconds t2 = 42us;
std::chrono::milliseconds t3 = 51ms;
std::chrono::seconds t4 = 61s;
std::chrono::minutes t5 = 88min;
auto t6 = 2 * 0.5h;
https://riptutorial.com/ 818
auto total = t1 + t2 + t3 + t4 + t5 + t6;
std::cout.precision(13);
std::cout << total.count() << " nanoseconds" << std::endl; // 8941051042600 nanoseconds
std::cout << std::chrono::duration_cast<std::chrono::hours>(total).count()
<< " hours" << std::endl; // 2 hours
}
C++14
Those following string user literals are declared in the namespace std::literals::string_literals,
where both literals and string_literals are inline namespaces. Access to these operators can be
gained with using namespace std::literals, using namespace std::string_literals, and using
namespace std::literals::string_literals.
#include <codecvt>
#include <iostream>
#include <locale>
#include <string>
int main()
{
using namespace std::literals::string_literals;
Note:
C++14
https://riptutorial.com/ 819
Those following complex user literals are declared in the namespace std::literals::complex_literals
, where both literals and complex_literals are inline namespaces. Access to these operators can
be gained with using namespace std::literals, using namespace std::complex_literals, and using
namespace std::literals::complex_literals.
#include <complex>
#include <iostream>
int main()
{
using namespace std::literals::complex_literals;
std::cout << "abs" << c << " = " << abs(c) << std::endl; // abs(2,1) = 2.23607
std::cout << "abs" << cf << " = " << abs(cf) << std::endl; // abs(2,1) = 2.23607
std::cout << "abs" << cl << " = " << abs(cl) << std::endl; // abs(2,1) = 2.23607
}
here comes a famous example with a self-made implementation for binary numbers:
#include <iostream>
int main()
{
std::cout << 10101_B << ", " << 011011000111_b << '\n' ; // prints 21, 1735
}
https://riptutorial.com/ 820
Read User-Defined Literals online: https://riptutorial.com/cplusplus/topic/2745/user-defined-literals
https://riptutorial.com/ 821
Chapter 142: Using declaration
Introduction
A using declaration introduces a single name into the current scope that was previously declared
elsewhere.
Syntax
• using typename(opt) nested-name-specifier unqualified-id;
• using :: unqualified-id;
Remarks
A using-declaration is distinct from a using directive, which tells the compiler to look in a particular
namespace when looking up any name. A using-directive begins with using namespace.
A using-declaration is also distinct from an alias declaration, which gives a new name to an
existing type in the same manner as typedef. An alias declaration contains an equals sign.
Examples
Importing names individually from a namespace
Once using is used to introduce the name cout from the namespace std into the scope of the main
function, the std::cout object can be referred to as cout alone.
#include <iostream>
int main() {
using std::cout;
cout << "Hello, world!\n";
}
Often, the name redeclared is one that would otherwise be hidden. For example, in the below
code, d1.foo only refers to Derived1::foo(const char*) and a compilation error will occur. The
function Base::foo(int) is hidden not considered at all. However, d2.foo(42) is fine because the
using-declaration brings Base::foo(int) into the set of entities named foo in Derived2. Name lookup
then finds both foos and overload resolution selects Base::foo.
struct Base {
https://riptutorial.com/ 822
void foo(int);
};
struct Derived1 : Base {
void foo(const char*);
};
struct Derived2 : Base {
using Base::foo;
void foo(const char*);
};
int main() {
Derived1 d1;
d1.foo(42); // error
Derived2 d2;
d2.foo(42); // OK
}
Inheriting constructors
C++11
As a special case, a using-declaration at class scope can refer to the constructors of a direct base
class. Those constructors are then inherited by the derived class and can be used to initialize the
derived class.
struct Base {
Base(int x, const char* s);
};
struct Derived1 : Base {
Derived1(int x, const char* s) : Base(x, s) {}
};
struct Derived2 : Base {
using Base::Base;
};
int main() {
Derived1 d1(42, "Hello, world");
Derived2 d2(42, "Hello, world");
}
In the above code, both Derived1 and Derived2 have constructors that forward the arguments
directly to the corresponding constructor of Base. Derived1 performs the forwarding explicitly, while
Derived2, using the C++11 feature of inheriting constructors, does so implicitly.
https://riptutorial.com/ 823
Chapter 143: Using std::unordered_map
Introduction
std::unordered_map is just an associative container. It works on keys and their maps. Key as the
names goes, helps to have uniqueness in the map. While the mapped value is just a content that
is associated with the key. The data types of this key and map can be any of the predefined data
type or user-defined.
Remarks
As the name goes, the elements in unordered map are not stored in sorted sequence. They are
stored according to their hash values and hence, usage of unordered map has many benefits such
as it only takes O(1) to search any item from it. It is also faster than other map containers. It is also
visible from the example that it is very easy to implement as the operator ( [] ) helps us to directly
access the mapped value.
Examples
Declaration and Usage
As already mentioned you can declare an unordered map of any type. Let's have a unordered
map named first with string and integer type.
https://riptutorial.com/ 824
unordered-map
https://riptutorial.com/ 825
Chapter 144: Value and Reference Semantics
Examples
Deep copying and move support
If a type wishes to have value semantics, and it needs to store objects that are dynamically
allocated, then on copy operations, the type will need to allocate new copies of those objects. It
must also do this for copy assignment.
This kind of copying is called a "deep copy". It effectively takes what would have otherwise been
reference semantics and turns it into value semantics:
public:
Value() : array_(new Inner[NUM_INNER]){}
C++11
Move semantics allow a type like Value to avoid truly copying its referenced data. If the user uses
the value in a way that provokes a move, the "copied" from object can be left empty of the data it
referenced:
https://riptutorial.com/ 826
public:
Value() : array_(new Inner[NUM_INNER]){}
Indeed, we can even make such a type non-copyable, if we want to forbid deep copies while still
allowing the object to be moved around.
public:
Value() : array_(new Inner[NUM_INNER]){}
https://riptutorial.com/ 827
{
//We've stolen the old value.
val.array_ = nullptr;
}
We can even apply the Rule of Zero, through the use of unique_ptr:
public:
Value() : array_(new Inner[NUM_INNER]){}
Definitions
A type has value semantics if the object's observable state is functionally distinct from all other
objects of that type. This means that if you copy an object, you have a new object, and
modifications of the new object will not be in any way visible from the old object.
int i = 5;
int j = i; //Copied
j += 20;
std::cout << i; //Prints 5; i is unaffected by changes to j.
https://riptutorial.com/ 828
std::vector<int> v1(5, 12); //array of 5 values, 12 in each.
std::vector<int> v2 = v1; //Copies the vector.
v2[3] = 6; v2[4] = 9;
std::cout << v1[3] << " " << v1[4]; //Writes "12 12", since v1 is unchanged.
A type is said to have reference semantics if an instance of that type can share its observable
state with another object (external to it), such that manipulating one object will cause the state to
change within another object.
C++ pointers have value semantics with regard to which object they point to, but they have
reference semantics with regard to the state of the object they point to:
https://riptutorial.com/ 829
Chapter 145: Value Categories
Examples
Value Category Meanings
Expressions in C++ are assigned a particular value category, based on the result of those
expressions. Value categories for expressions can affect C++ function overload resolution.
The other property is whether it is legal to implicitly move from the expression's value. Or more
specifically, whether the expression, when used as a function parameter, will bind to r-value
parameter types or not.
C++ defines 3 value categories which represent the useful combination of these properties: lvalue
(expressions with identity but not movable from), xvalue (expressions with identity that are
moveable from), and prvalue (expressions without identity that are moveable from). C++ does not
have expressions which have no identity and cannot be moved from.
C++ defines two other value categories, each based solely on one of these properties: glvalue
(expressions with identity) and rvalue (expressions that can be moved from). These act as useful
groupings of the prior categories.
prvalue
https://riptutorial.com/ 830
are not limited to:
xvalue
An xvalue (eXpiring value) expression is an expression which has identity and represents an
object which can be implicitly moved from. The general idea with xvalue expressions is that the
object they represent is going to be destroyed soon (hence the "eXpiring" part), and therefore
implicitly moving from them is fine.
Given:
struct X { int n; };
extern X x;
lvalue
An lvalue expression is an expression which has identity, but cannot be implicitly moved from.
Among these are expressions that consist of a variable name, function name, expressions that are
built-in dereference operator uses and expressions that refer to lvalue references.
The typical lvalue is simply a name, but lvalues can come in other flavors as well:
struct X { ... };
X x; // x is an lvalue
X* px = &x; // px is an lvalue
*px = X{}; // *px is also an lvalue, X{} is a prvalue
Additionally, while most literals (e.g. 4, 'x', etc.) are prvalues, string literals are lvalues.
glvalue
https://riptutorial.com/ 831
A glvalue (a "generalized lvalue") expression is any expression which has identity, regardless of
whether it can be moved from or not. This category includes lvalues (expressions that have
identity but can't be moved from) and xvalues (expressions that have identity, and can be moved
from), but excludes prvalues (expressions without identity).
struct X { int n; };
X foo();
X x;
x; // has a name, so it's a glvalue
std::move(x); // has a name (we're moving from "x"), so it's a glvalue
// can be moved from, so it's an xvalue not an lvalue
rvalue
An rvalue expression is any expression which can be implicitly moved from, regardless of whether
it has identity.
More precisely, rvalue expressions may be used as the argument to a function that takes a
parameter of type T && (where T is the type of expr). Only rvalue expressions may be given as
arguments to such function parameters; if a non-rvalue expression is used, then overload
resolution will pick any function that does not use an rvalue reference parameter. And if none
exist, then you get an error.
The category of rvalue expressions includes all xvalue and prvalue expressions, and only those
expressions.
The standard library function std::move exists to explicitly transform a non-rvalue expression into
an rvalue. More specifically, it turns the expression into an xvalue, since even if it was an identity-
less prvalue expression before, by passing it as a parameter to std::move, it gains identity (the
function's parameter name) and becomes an xvalue.
std::string has a constructor which takes a single parameter of type std::string&&, commonly
called a "move constructor". However, the value category of the expression str is not an rvalue
(specifically it is an lvalue), so it cannot call that constructor overload. Instead, it calls the const
std::string&
https://riptutorial.com/ 832
overload, the copy constructor.
Line 3 changes things. The return value of std::move is a T&&, where T is the base type of the
parameter passed in. So std::move(str) returns std::string&&. A function call who's return value is
an rvalue reference is an rvalue expression (specifically an xvalue), so it may call the move
constructor of std::string. After line 3, str has been moved from (who's contents are now
undefined).
Line 4 passes a temporary to the assignment operator of std::string. This has an overload which
takes a std::string&&. The expression std::string("new value") is an rvalue expression
(specifically a prvalue), so it may call that overload. Thus, the temporary is moved into str,
replacing the undefined contents with specific contents.
Line 5 creates a named rvalue reference called str_ref that refers to str. This is where value
categories get confusing.
See, while str_ref is an rvalue reference to std::string, the value category of the expression
str_ref is not an rvalue. It is an lvalue expression. Yes, really. Because of this, one cannot call the
move constructor of std::string with the expression str_ref. Line 6 therefore copies the value of
str into test3.
https://riptutorial.com/ 833
Chapter 146: Variable Declaration Keywords
Examples
const
A type specifier; when applied to a type, produces the const-qualified version of the type. See
const keyword for details on the meaning of const.
struct S {
void f();
void g() const;
};
const S s;
s.f(); // error
s.g(); // OK
decltype
C++11
• If the operand e is a name without any additional parentheses, then decltype(e) is the
declared type of e.
int x = 42;
std::vector<decltype(x)> v(100, x); // v is a vector<int>
• If the operand e is a class member access without any additional parentheses, then
decltype(e) is the declared type of the member accessed.
struct S {
int x = 42;
};
const S s;
decltype(s.x) y; // y has type int, even though s.x is const
• In all other cases, decltype(e) yields both the type and the value category of the expression e
, as follows:
https://riptutorial.com/ 834
This includes the case with extraneous parentheses.
C++14
The special form decltype(auto) deduces the type of a variable from its initializer or the return type
of a function from the return statements in its definition, using the type deduction rules of decltype
rather than those of auto.
signed
• When used alone, int is implied, so that signed, signed int, and int are the same type.
• When combined with char, yields the type signed char, which is a different type from char,
even if char is also signed. signed char has a range that includes at least -127 to +127,
inclusive.
• When combined with short, long, or long long, it is redundant, since those types are already
signed.
• signed cannot be combined with bool, wchar_t, char16_t, or char32_t.
Example:
unsigned
• When used alone, int is implied, so unsigned is the same type as unsigned int.
• The type unsigned char is different from the type char, even if char is unsigned. It can hold
integers up to at least 255.
• unsigned can also be combined with short, long, or long long. It cannot be combined with bool
, wchar_t, char16_t, or char32_t.
Example:
https://riptutorial.com/ 835
char invert_case_table[256] = { ..., 'a', 'b', 'c', ..., 'A', 'B', 'C', ... };
char invert_case(char c) {
unsigned char index = c;
return invert_case_table[index];
// note: returning invert_case_table[c] directly does the
// wrong thing on implementations where char is a signed type
}
volatile
A type qualifier; when applied to a type, produces the volatile-qualified version of the type. Volatile
qualification plays the same role as const qualification in the type system, but volatile does not
prevent objects from being modified; instead, it forces the compiler to treat all accesses to such
objects as side effects.
In the example below, if memory_mapped_port were not volatile, the compiler could optimize the
function so that it performs only the final write, which would be incorrect if sizeof(int) is greater
than 1. The volatile qualification forces it to treat all sizeof(int) writes as different side effects and
hence perform all of them (in order).
https://riptutorial.com/ 836
Chapter 147: Virtual Member Functions
Syntax
• virtual void f();
• // C++11 or later:
Remarks
• Only non-static, non-template member functions can be virtual.
• If you are using C++11 or later, it is recommended to use override when overriding a virtual
member function from a base class.
• Polymorphic base classes often have virtual destructors to allow a derived object to be
deleted through a pointer to the base class. If the destructor were not virtual, such an
operation leads to undefined behavior[expr.delete] §5.3.5/3 .
Examples
Using override with virtual in C++11 and later
The specifier override has a special meaning in C++11 onwards, if appended at the end of
function signature. This signifies that a function is
There is no run time significance of this specifier as is mainly meant as an indication for compilers
The example below will demonstrate the change in behaviour with our without using override.
Without override:
#include <iostream>
struct X {
virtual void f() { std::cout << "X::f()\n"; }
};
struct Y : X {
https://riptutorial.com/ 837
// Y::f() will not override X::f() because it has a different signature,
// but the compiler will accept the code (and silently ignore Y::f()).
virtual void f(int a) { std::cout << a << "\n"; }
};
With override:
#include <iostream>
struct X {
virtual void f() { std::cout << "X::f()\n"; }
};
struct Y : X {
// The compiler will alert you to the fact that Y::f() does not
// actually override anything.
virtual void f(int a) override { std::cout << a << "\n"; }
};
Note that override is not a keyword, but a special identifier which only may appear in function
signatures. In all other contexts override still may be used as an identifier:
void foo() {
int override = 1; // OK.
int virtual = 2; // Compilation error: keywords can't be used as identifiers.
}
#include <iostream>
struct X {
virtual void f() { std::cout << "X::f()\n"; }
};
struct Y : X {
// Specifying virtual again here is optional
// because it can be inferred from X::f().
virtual void f() { std::cout << "Y::f()\n"; }
};
void call(X& a) {
a.f();
}
int main() {
X x;
Y y;
call(x); // outputs "X::f()"
call(y); // outputs "Y::f()"
}
https://riptutorial.com/ 838
Without virtual member functions:
#include <iostream>
struct X {
void f() { std::cout << "X::f()\n"; }
};
struct Y : X {
void f() { std::cout << "Y::f()\n"; }
};
void call(X& a) {
a.f();
}
int main() {
X x;
Y y;
call(x); // outputs "X::f()"
call(y); // outputs "X::f()"
}
C++11 introduced final specifier which forbids method overriding if appeared in method signature:
class Base {
public:
virtual void foo() {
std::cout << "Base::Foo\n";
}
};
The specifier final can only be used with `virtual' member function and can't be applied to non-
virtual member functions
Like final, there is also an specifier caller 'override' which prevent overriding of virtual functions
in the derived class.
https://riptutorial.com/ 839
The specifiers override and final may be combined together to have desired effect:
The behaviour of virtual functions in constructors and destructors is often confusing when first
encountered.
#include <iostream>
using namespace std;
class base {
public:
base() { f("base constructor"); }
~base() { f("base destructor"); }
};
int main() {
derived d;
}
Output:
The reasoning behind this is that the derived class may define additional members which are not
yet initialized (in the constructor case) or already destroyed (in the destructor case), and calling its
member functions would be unsafe. Therefore during construction and destruction of C++ objects,
the dynamic type of *this is considered to be the constructor's or destructor's class and not a
more-derived class.
https://riptutorial.com/ 840
Example:
#include <iostream>
#include <memory>
int main() {
derived d(4);
}
We can also specify that a virtual function is pure virtual (abstract), by appending = 0 to the
declaration. Classes with one or more pure virtual functions are considered to be abstract, and
cannot be instantiated; only derived classes which define, or inherit definitions for, all pure virtual
functions can be instantiated.
struct Abstract {
virtual void f() = 0;
};
struct Concrete {
void f() override {}
};
Abstract a; // Error.
Concrete c; // Good.
Even if a function is specified as pure virtual, it can be given a default implementation. Despite
this, the function will still be considered abstract, and derived classes will have to define it before
they can be instantiated. In this case, the derived class' version of the function is even allowed to
call the base class' version.
struct DefaultAbstract {
virtual void f() = 0;
};
void DefaultAbstract::f() {}
https://riptutorial.com/ 841
struct WhyWouldWeDoThis : DefaultAbstract {
void f() override { DefaultAbstract::f(); }
};
• If we want to create a class that can't itself be instantiated, but doesn't prevent its derived
classes from being instantiated, we can declare the destructor as pure virtual. Being the
destructor, it must be defined anyways, if we want to be able to deallocate the instance. And
as the destructor is most likely already virtual to prevent memory leaks during polymorphic
use, we won't incur an unnecessary performance hit from declaring another function virtual.
This can be useful when making interfaces.
struct Interface {
virtual ~Interface() = 0;
};
Interface::~Interface() = default;
• If most or all implementations of the pure virtual function will contain duplicate code, that
code can instead be moved to the base class version, making the code easier to maintain.
class SharedBase {
State my_state;
std::unique_ptr<Helper> my_helper;
// ...
public:
virtual void config(const Context& cont) = 0;
// ...
};
/* virtual */ void SharedBase::config(const Context& cont) {
my_helper = new Helper(my_state, cont.relevant_field);
do_this();
and_that();
}
public:
void config(const Context& cont) override;
// ...
};
void OneImplementation::config(const Context& cont) /* override */ {
my_state = { cont.some_field, cont.another_field, i };
SharedBase::config(cont);
my_unique_setup();
};
https://riptutorial.com/ 842
Read Virtual Member Functions online: https://riptutorial.com/cplusplus/topic/1752/virtual-member-
functions
https://riptutorial.com/ 843
Credits
S.
Chapters Contributors
No
Argument Dependent
3 Fanael, Johannes Schaub - litb
Name Lookup
Arithmitic
4 Meena Alfons
Metaprogramming
https://riptutorial.com/ 844
Jarod42, Johan Lundberg, manlio, Yakk
Basic input/output in
9 Daemon, Nicol Bolas, Владимир Стрелец
c++
15 C incompatibilities パスカル
C++11 Memory
20 NonNumeric
Model
Client server
23 Abhinav Gauniyal
examples
Common
24 Asu, immerhart
compile/linker errors
https://riptutorial.com/ 845
(GCC)
Concurrency With
26 Andrea Chua, JVApen, Nicol Bolas, Sumurai8
OpenMP
Constant class
29 Vijayabhaskarreddy CH, Yakk
member functions
Copying vs
32 amanuel2, Roland
Assignment
Curiously Recurring
33 Template Pattern Barry, Brian, Gabriel, honk, Nicol Bolas, Ryan Haining
(CRTP)
Data Structures in
34 Gaurav Sehgal
C++
36 decltype Ajay
Design pattern
Antonio Barreto, datosh, didiz, Jarod42, JVApen, Nikola
37 implementation in
Vasilev
C++
https://riptutorial.com/ 846
Alexey Guseynov, Brian, callyalater, Dr t, Jahid, Jarod42,
40 Exceptions Johan Lundberg, jotik, Martin Ba, Nemanja Boric, Null, Peter,
Rakete1111, Ronen Ness
Explicit type
41 4444, Brian, JVApen, Nikola Vasilev
conversions
Floating Point
44 Xirema
Arithmetic
Function Template
49 Johannes Schaub - litb, Kunal Tyagi, RamenChef
Overloading
Internationalization in
55 John Bargman
C++
https://riptutorial.com/ 847
Brian, Daniel Käfer, Emmanuel Mathi-Amorim, marquesm91,
56 Iteration
RamenChef
More undefined
66 didiz
behaviors in C++
https://riptutorial.com/ 848
69 Mutexes didiz, hyoslee, JVApen
Non-Static Member
71 Justin Time, RamenChef
Functions
https://riptutorial.com/ 849
RAII: Resource
Barry, defube, Jarod42, JVApen, Loki Astari, Niall, Nicol Bolas,
86 Acquisition Is
RamenChef, Sumurai8, Tannin
Initialization
Random number
87 Ha., manlio, merlinND, Sumurai8
generation
Resource
93 Anonymous1847
Management
Return Type
94 Cheers and hth. - Alf, sorosh_sabz
Covariance
RTTI: Run-Time Type Brian, deepmax, Pankaj Kumar Boora, Roland, Savas Mikail
96
Information KAPLAN
98 Semaphore didiz
SFINAE (Substitution
Barry, Fox, Jarod42, Jason R, Jonathan Lee, Luc Danton,
99 Failure Is Not An
sp2danny, SU3, w1th0utnam3, Xosdy, Yakk
Error)
Side by Side
Comparisons of
100 classic C++ examples wasthishelpful
solved via C++ vs
C++11 vs C++14 vs
https://riptutorial.com/ 850
C++17
Singleton Design
101 deepmax, Galik, Jarod42, Johan Lundberg, JVApen, Stradigos
Pattern
Special Member
104 Barry, krOoze, OliPro007, Reuben Thomas, TriskalJM
Functions
106 static_assert Jarod42, JVApen, lorro, Marco A., Richard Dally, T.C.
std::function: To wrap
111 any element that is elimad, Evgeniy, Nicol Bolas, Tarod
callable
https://riptutorial.com/ 851
115 std::optional Barry, diegodfrf, Jahid, Jared Payne, JVApen, Null, Yakk
std::set and
117 G-Man, JVApen, Mikitori
std::multiset
Storage class
121 Brian, start2learn
specifiers
https://riptutorial.com/ 852
Barry, Benjy Kessler, Brian, callyalater, cb4, celtschk,
CodeMouse92, Colin Basnett, DeepCoder, Diligent Key
Presser, Eldritch Cheese, eXPerience, FedeWar, Gabriel,
Greg, Holt, honk, J_T, Johannes Schaub - litb, Justin, JVApen,
123 Templates
Loki Astari, M. Viaz, manlio, Maxito, MSalters, Nicol Bolas,
Pontus Gagge, Praetorian, Rakete1111, Ricardo Amores,
Ryan Haining, Sergey, SirGuy, Smeeheey, Sumurai8,
user1887915, W.F., WMios, Wolf, πάντα ῥεῖ
Thread
127 synchronization didiz, Galik, JVApen
structures
https://riptutorial.com/ 853
Schaub - litb, JVApen, kd1508, Ken Y-N, manetsus, manlio,
Marco A., Mat, mceo, Motti, Naor Hadar, nbro, Nicol Bolas,
Peter, Rakete1111, ralismark, RamenChef, Sebastian Ärleryd,
Tannin, Trevor Hickey, Tyler Durden
Using
143 tulak.hord
std::unordered_map
Variable Declaration
146 Brian, RamenChef, start2learn
Keywords
Virtual Member 0x5f3759df, Daksh Gupta, Johan Lundberg, Justin Time, Motti,
147
Functions Sergey, T.C.
https://riptutorial.com/ 854