I started learning C++ with Turbo C++ and left programming in C++ with Microsoft Visual C++ MFC. It has been over 20 years since and C++ has evolved so much.

sudo apt install g++
sudo apt install g++-10
sudo apt install make
g++ --version
shows the current version, which is 9.3.0
and g++-10 --version
shows 10.2.0
Compile:
cc hello.cpp -o hello
#include "stdio.h"
int main() {
printf("Hello World!\n");
}
Using GNU make, here is the Makefile
:
CC = g++-10
CFLAGS = -g -std=c++20
OBJ := $(patsubst %.cpp,%.o,$(wildcard *.cpp))
main: $(OBJ)
$(CC) -o main $(OBJ) $(CFLAGS)
%.o: %.cpp
$(CC) -c -o $@ $< $(CFLAGS)
clean:
rm -f *.o main
The main.cpp
file:
#include <iostream>
int main() {
std::cout << "Hello World!" << std::endl;
return 0;
}
Include header-file only once like this:
#ifndef USER_H
#define USER_H
class User {};
#endif
CMake
I will be using CMake.
sudo apt install cmake
Here is the CMakeList.txt
:
cmake_minimum_required(VERSION 3.10)
project(Program VERSION 1.0)
configure_file(ProgramConfig.h.in ProgramConfig.h)
target_include_directories(Program PUBLIC "${PROJECT_BINARY_DIR}")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror -std=c++2a")
set (source_dir "${PROJECT_SOURCE_DIR}/src/")
file (GLOB source_files "${source_dir}/*.cpp")
add_executable (Program ${source_files})
ProgramConfig.h.in
#define Program_VERSION_MAJOR @Program_VERSION_MAJOR@
#define Program_VERSION_MINOR @Program_VERSION_MINOR@
(todo: Explore more CMake features)
Debug with GDB
Use the compiler flag -g
to add debug infos to the executable.
A debug session could go like this:
- Start with
gdb main --tui
where main is the executable. - Set break-point
b 34
- Step over to next line
n
- Step into code/next line
s
- Show variable
p data
- End
q
Attach to a running process:
gdb executable --pid=process-id --tui
Commands | |
---|---|
b line-number | Break at line line-number |
n | Step over to next line |
s | Step into next line |
c | Continue running |
l | Print source code |
p variable-name | Print contents of variable |
d | Delete breakpoint |
q | Exit |
r | Run |
C++ Language
Here are my notes about the current C++ language.
Variables
Use auto
to declare variables whenever possible. It helps to avoid unintentional conversion, improves readability and is easier to maintain.
auto i = 1;
C++14 digital separators auto i = 1'000'000'000;
auto i{1};
auto i = {1}
`auto s = "This is a std::string"s;
C++14 binary digitals auto x = 0b00110101;
Constexpr template with variables:
template <typename T>
constexpr T pi = T{3.14159};
template <>
constexpr int pi<int>{3};
int main() {
std::cout << pi<double> << std::endl;
std::cout << pi<int> << std::endl;
return 0;
}
Flow control
for (auto i : array) { }
for (auto& n : array) { n += 2; }
for (auto const& e : entries) { }
C++17 declare variables in if- and switch-block
if (const auto x = get_x(); x < 10) {
}
switch (const auto x = get_x(); ...) {
}
C++17 if constexpr
is evaluated by the compiler
if constexpr (x == 1) {
} else {
}
Enum
enum class AccountType { A, B, C };
Strings
std::string
, std::wstring
, std::string_view
auto s1 = "Hello World!"s
;std::stod
- string to floating pointstd::stol
- string to integer- Date, Time: std::tm, std::get_time
- Vector: begin, end,
find_if
Raw strings:
const char* str = R"";
Regex
#include <regex>
int main() {
std::string s = "This is the text we apply a regular expression on.\n"
"\"Start this in a new line in double-quotes.\"";
std::regex a_regex("Quote", std::regex_constants::icase);
if (std::regex_search(s, a_regex)) {
std::cout << "Found!" << std::endl;
}
return 0;
}
Functions
inline void f() noexcept {
}
auto g(double x) {
return x * x;
}
[[deprecated]]
void h() {
}
[[deprecated("Use f instead.")]]
void g() {
}
Use braced bracket initialization to call f()
.
struct Point {
int x;
int y;
}
void f(Point p) {
}
int main() {
f({1, 2});
}
noexcept
is used for compile-time optimization. There is a noexcept()
operator that can give the info at compile-time whether an expression can throw an exception.
-
Use
inline
for small functions (containing 1-2 statements) -
Use snake-case for function names.
-
Place
{
not in separate line (Ignore the exception for{
for functions in NL.17 of the C++ Core Guidelines, no separate line required)A function can have unnamed parameters. This is to indicate that the parameter is not used but keep the interface the same. Either because the caller cannot be changed or because to implement a virtual function of a base class.
Classes
class
and struct
are basically the same with public access as default for struct
and private for class
. A struct
class cannot be used in template parameter typename
.
A class can extend from a struct and the other way round too.
struct A {
int a{1};
};
class B: protected A {
public:
int b{2};
};
struct C: B {
int c{3};
};
Constructor explicit
default
deleted
Member functions virtual
mutable
in member variable declaration- nested
class
declaration typdef class
forward declaration in surrounding class
std::get
std::get_if
Use Pascal-case for class-names.
Friend
#include <iostream>
class B;
class A {
friend class B;
std::string sentence{"I'm A."};
public:
void say_hello(A& a, B& b) {
std::cout << "A:" << std:: endl;
std::cout << a.sentence << std::endl;
// A is not friend of B
// std::cout << b.sentence << std::endl;
}
};
class B {
std::string sentence{"I'm B."};
public:
void say_hello(A& a, B& b) {
std::cout << "B:" << std::endl;
std::cout << a.sentence << std::endl;
std::cout << b.sentence << std::endl;
}
friend void say_hello_friend(A&, B& b) {
// this function is not friend of A but has full access to B and is not member of B
// std::cout << a.sentence << std::endl;
std::cout << "Friend function of B:" << std::endl;
std::cout << b.sentence << std::endl;
}
};
int main() {
const A a;
const B b;
a.say_hello(a, b);
b.say_hello(a, b);
// say_hello_friend is not mbember of B
// b.say_hello_friend(a, b);
say_hello_friend(a, b);
return 0;
}
RAII - Resource Acquisition is Initialization
Ref-Qualifier
Member functions and operator overloading can have a lvalue or a rvalue ref-qualifier
.
Mixing with non-ref-qualifier
is not allowed.
struct A {
void f();
void g() &; // lvalue ref-qualifier
void g() &&; // rvalue ref-qualifier
void h(); // error, mixing not allowed
void h() &; // error, mixing not allowed
void i() &;
void i() const &;
A* operator &() &; // only lvalue allowed
A& operator =(A const&) &; // only lvalue allowed
};
int main() {
A* pA = &A(); // does not compile
A() = A(); // does not compile
}
Use ref-qualifier to differentiate between move and copy.
class B {
std::vector<char> data;
public:
std::vector<char> const& get_data() const & {
return data;
}
std::vector<char>&& get_data() && {
return std::move(data);
}
};
int main() {
B b;
std::vector<char> i = b.get_data(); // copy
std::vector<char> j = (B()).get_data(); // move
}
CTAD Class Template Argument Deduction
Const
First const
can be placed either side of type:
const int * const
== int const * const
Placing it after is more consistent but it is against the C++ Core Guidelines. The guidelines is inconsistent with the exception to the rule.
int const three = 3;
- Local variable
for (auto const& e : v)
- Local loop variable
void f(Quote const& q);
- Function parameter
int g() const;
- Member function does not change member variables.
volatile
indicate to the compiler not to do some type of optimization.
mutable
specifier for non static
class member. It makes a const
class member mutable. Used in context with std::mutex
.
Constexpr
With constexpr
the compiler can evaluate and optimize at compile-time.
constexpr int f(int x) {}
constexpr int y = f(1);
Lambdas
Lambdas: [](){} vs function objects
[]
- Contains capture of variables. Default is by value.
[a, &b]
- a
by value and b
by reference.
`[c = 12] - Init capture.
Capture a non-copyable variable by moving:
std::unique_ptr<A> a;
auto lambda = [b{std::move(a)}]()( *b = };
int main() {
std::vector<int> v{4, 1, 4, 1, 3, 6, 3, 7, 2, 3, 6, 4};
for_each(begin(v), end(v), [](int i) { std::cout << i << ";"; });
}
`std::visit`
### Destructuring, std::tuple
Since C++17 destructuring assignment on declaring variables is available. Similar to JavaScript but only for declaring variables.
```cpp
std::tuple<int, double, std::string> split(std::string const& line) {
// do the split
return std::make_tuple(3, 3.1415, "pi");
}
...
auto [id, value, name] = split("3; 3.1415; pi");
auto second = std::get<1>(split("3; 3.1415; pi"));
auto third = std::get<std::string>(split("3; 3.1415; pi"));
int a = 0;
double b;
std::string c;
std::tie(std::ignore, b, c) = split("...");
std::pair
std::make_tuple
- Create a tuple.
std::get
- Get value out of a tuple.
std::tie
- Create a tuple of lvalue references.
std::ignore
- Placeholder for std::tie
Fold Expression
C++17 Using the ...
to indicate a fold expression.
Pointers
nullptr
represents null
std::unique_ptr
Use nullptr
instead NULL
- If one of copy constructor, destructor, copy assignment operator is defined, then define all three.
decltype
// todo add decltype code
Move Semantics
Back to Basics: Move Semantics p1 Back to Basics: Move Semantics p2
Templates
std::any
std::optional
SFINAE - Substitution Failure Is Not An Error (What's that?)
Exceptions
throw std::runtime_error("some resource could not be allocated");
try {
} catch (std::bad_variant_access const& e) {
std::cout << e.what() << std::endl;
}
Operator Overloading
#include <iostream>
struct Point {
int x;
int y;
/*
constexpr bool operator==(const Point& rhs) const noexcept { return (x == rhs.x) && (y == rhs.y); }
*/
constexpr bool operator==(const Point&) const noexcept = default;
constexpr auto operator<=>(const Point&) const noexcept = default;
};
int main() {
Point p1 = {1, 1};
Point p2 = {1, 2};
Point p3 = {1, 1};
auto eq1 = p1 == p2;
auto eq2 = !(p1 != p2);
auto eq3 = !(p1 != p3);
std::cout << "eq1 " << eq1 << std::endl;
std::cout << "eq2 " << eq2 << std::endl;
std::cout << "eq3 " << eq3 << std::endl;
auto threeway = (p1 <=> p2) < 0; // less
auto threeway2 = (p2 <=> p1) > 0; // greater
auto threeway3 = (p1 <=> p3) == 0; // equal
std::cout << "threeway " << threeway << std::endl;
std::cout << "threeway2 " << threeway2 << std::endl;
std::cout << "threeway3 " << threeway3 << std::endl;
Point p4 = {2, 1};
auto threeway4 = (p2 <=> p4) == 0; // equal
auto threeway5 = (p2 <=> p4) < 0; // equal
std::cout << "threeway4 " << threeway4 << std::endl; // 0
std::cout << "threeway5 " << threeway5 << std::endl; // 1
return 0;
}
Casting
Attributes
variant instead unions
std::variant
Files and Streams
- Read/write files
Network I/O
Socktes, Web-Sockets
Threads
std::thread
std::async
std::promise
std::future
Avoid static
, use thread_local
instead.
Avoid global data.
Protect static
variables with static std::mutex
.
Coroutines
Constraints and Concepts
C++20: concept
requires
STL Standard Library
std::array
Functions | |
---|---|
swap | Swaps the contents of two arrays. |
std::vector
Functions | |
---|---|
capacity | - |
clear | - |
insert | - |
pop_back | - |
push_back | - |
reverse | - |
shrink_to_fit | - |
size | - |
std <algorithm>: all_of, none_of, any_of
for_each, copy, copy_if
Operations with Iterators | |
---|---|
std::distance | Returns the steps used to get from first past the last. |
std::inplace_merge | Merges two sorted ranges into one sorted range. |
std::partition | Separates a list of elements by a predicate so that true elements comes before false elements. |
std::sort | Sort a list of elements. |
std::unique | Make a list of elements unique by deleting elements except the first of the same. |
std::count_if |
#include <iostream>
#include <algorithm>
#include <vector>
int main() {
std::vector<int> v{4, 1, 4, 1, 3, 6, 3, 7, 2, 3, 1, 4};
for_each(begin(v), end(v), [](auto e){ std::cout << e << " "; });
copy(begin(v), end(v), std::ostream_iterator<int>(std::cout, " "));
auto all = all_of(begin(v), end(v), [](auto e){ return e == 4; });
auto any = any_of(begin(v), end(v), [](auto e){ return e == 4; });
auto none = none_of(begin(v), end(v), [](auto e){ return e == 4; });
std::cout << std::endl << "all_of any_of none_of" << std::endl;
std::cout << all << " " << any << " " << none << std::endl;
return 0;
}
std: atomic
variant, visit
std <numeric>: partical_sum
std::min
- Function returns min of two or min of begin and end iterator. An optional comarator can be supplied.
std::max
- Function returns max of two or max of begin and end iterator. An optional comparator can be supplied.
std::max_element
- (What is the difference to std::max?)
std::stable_sort
- Sorts elements where the present order of equal elements are preserved.
std::sqrt
- Square-root function.
std::numeric_limits
std::binary_function
std::swap
- Swap two values.
std::queue
std::random_device
std::ranlux48
- 48-bit RANLUX generator
std::istringstream
std::ostringstream
std::isalpha
std::isdigit
WebAssembly
Database Access
Efficiency and Performance
Compare generated output in assembly language:
g++ -S main.cpp
g++ -masm=intel -S main.cpp
or
objdump -M intel -S --disassemble main.o > main.s
std::chrono
performance measurements
Branch prediction (fewer branches, deterministic)
- Do as much as possible at compile time
- Pre-populated data-structure
- Rearrange statements and blocks
- Trust private code and do less validation
- Watch out for
virtual
methods and replace withtemplate
(CRTP Curiously recurring template pattern) (memory vs runtime) - C++20 Use
[[likely]]
and[[unlikely]]
to help the compiler - Data dependent, reorder data. Test the example on StackOverflow
Cash misses
-
Warmup criticall vip-code-path with skip-finally flag
-
No system calls
-
No memory allocation after warmup phase
-
No context switching (todo)
Web with C++
Crow - C++ micro web framework (comparable to Node.js + Express?) https://github.com/ipkn/crow
HttpLib - C++ header-only HTTP/s server/client library https://github.com/yhirose/cpp-httplib
Pistache - REST framework https://github.com/pistacheio/pistache
Restbed - REST framework https://github.com/Corvusoft/restbed
Restinio - C++ header-only HTTP/s server framework https://github.com/Stiffstream/restinio
Microsoft C++ REST SDK - (retired) https://github.com/microsoft/cpprestsdk
JSON
RapidJSON https://rapidjson.org/
Links and References
Standard C++ https://isocpp.org
C++ Reference https://en.cppreference.com/
C++ Core Guidelines http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines
Google C++ Style Guide https://google.github.io/styleguide/cppguide.html
Compiler Explorer https://godbolt.org
CPP Insights https://cppinsights.io/
Microsoft C++ Language Documentation https://docs.microsoft.com/en-us/cpp/cpp/
Cross-platform mobile development with C++
Boost C++ Libraries https://www.boost.org/
Boost.DI - Boost Dependency Injection https://github.com/boost-ext/di
LLVM Compiler https://llvm.org/
Node.js C++ addons https://nodejs.org/api/addons.html#addons_c_addons
Microsoft Guidelines Support Library https://github.com/Microsoft/GSL
C++ Draft http://eel.is/c++draft/
WG21 redirect service https://wg21.link/
Bloaty McBlatface - A size profiler for binaries https://github.com/google/bloaty
Blogs
Fluent {C++} - Jonathan Boccara https://www.fluentcpp.com/
Modernes C++ - Rainer Grimm https://www.grimm-jaud.de/index.php/blog
Exlpore
RmlUi - The HTML/CSS User Interface Library Evolved https://github.com/mikke89/RmlUi
Not Enough Standards - Platform-independent utilities https://github.com/Alairion/not-enough-standards