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.
Install tools:
sudo apt-get install g++
sudo apt-get install g++-10
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 = -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>
using std::cout;
using std::endl;
int main() {
cout << "Hello World!" << endl;
return 0;
}
CMake
I will be using CMake.
sudo apt-get 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@
Difference to C# and Java
new
has different meaning and is used to allocate memory in the heap. Use this with delete
in mind
const
is more widely used
virtual
must be used explicitely
this
this->name = name;
return *this;
References must be used explicitely.
Topic
- Explore more CMake features.
- Operator declaration and implementation with and without class.
- Casting:
const_cast
,dynamic_cast
,reinterpret_cast
,static_cast<int>(3.14)
- Learn more about current STL
- for_each, begin(), end(), move(), make_unique<>()
Variables
auto i = 1;
auto i{1};
auto i = {1}
auto x = 0b00110101;
Flow control
for (auto const& e : entries) { }
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, count_if, find_if
Functions
inline void f() noexcept {
}
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 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
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
std::visit
Destructuring, std::tuple
Since C++17 destructuring assignment on declaring variables is available. Similar to JavaScript but only for declaring variables.
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");
std::pair
Pointers
nullptr
represents null
std::unique_ptr
std::shared_ptr
Use nullptr
instead NULL
- If one of copy constructor, destructor, copy assignment operator is defined, then define all three.
Templates
std::any
std::optional
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>
using std::cout;
using std::endl;
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);
cout << "eq1 " << eq1 << endl;
cout << "eq2 " << eq2 << endl;
cout << "eq3 " << eq3 << endl;
auto threeway = (p1 <=> p2) < 0; // less
auto threeway2 = (p2 <=> p1) > 0; // greater
auto threeway3 = (p1 <=> p3) == 0; // equal
cout << "threeway " << threeway << endl;
cout << "threeway2 " << threeway2 << endl;
cout << "threeway3 " << threeway3 << endl;
Point p4 = {2, 1};
auto threeway4 = (p2 <=> p4) == 0; // equal
auto threeway5 = (p2 <=> p4) < 0; // equal
cout << "threeway4 " << threeway4 << endl; // 0
cout << "threeway5 " << threeway5 << endl; // 1
return 0;
}
Attributes
variant instead unions
std::variant
Files and Streams
- Read/write files
Network I/O
Socktes, Web-Sockets
Threads
std::thread
std::async
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 <algorithm>: all_of, none_of, any_of
#include <iostream>
#include <algorithm>
#include <vector>
using std::cout;
using std::vector;
using std::endl;
int main() {
vector<int> v{4, 1, 4, 1, 3, 6, 3, 7, 2, 3, 1, 4};
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; });
cout << "all_of any_of none_of" << endl;
cout << all << " " << any << " " << none << endl;
return 0;
}
std: atomic, variant, visit
std <numeric>: partical_sum
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)
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
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