C++


Basics


Usage

  • Cheat sheet is for C++ version 17. Formal name is ISO/IEC 14882:2017. Informal name is C++17, or C++1z.
  • I will be using GCC compiler. It is the default compiler on Linux. It is also available on Windows and Mac.
g++ -std=c++17 <filename>.cpp -o <filename>.x   # To compile the C++ main file

Note that in-order to shorten the length of a code-line, I will not write std:: in this cheat sheet. For example: instead of writing std::vector, I will simply write vector. If you want to do the same thing in your code, you need to add this line: using namespace std;. But, it is usually considered as a bad practice, see StackExchange.


Preprocessor

                            // Comment to end of line
                            /* Multi-line comment */
                            // .hpp denotes for C++ header files, and .h for C header files
#include <iostream>         // Insert C++ standard header file or library file; without .hpp
#include <stdio.h>          // Insert C standard header file or library file; with h
#include "myfile.h"         // Insert file in current directory
#define X some_text         // Replace X with some text
#define F(a,b) a+b          // Replace F(1,2) with 1+2
#define X \
 some text                  // Multiline definition
#undef X                    // Remove definition
#if defined(X)              // Conditional compilation (#ifdef X)
#else                       // Optional (#ifndef X or #if !defined(X))
#endif                      // Required after #if, #ifdef

πŸ” | More


Literals

  • The single quote is use to define single character and double quotes is use to define string literal.
255, 0377, 0xff             // Integers (decimal, octal, hex)
2147483647L, 0x7fffffffl    // Long (32-bit) integers
123.0, 1.23e2               // double (real) numbers
'a', '\141', '\x61'         // Character (literal, octal, hex)
'\n', '\\', '\'', '\"'      // Newline, backslash, single quote, double quote
"string\n"                  // Array of characters ending with newline and \0
"hello" " world"            // Concatenated strings
true, false                 // bool constants 1 and 0
nullptr                     // Pointer type with the address of 0

πŸ” | More


Declarations

int x;                                    // Declare x to be an integer (value undefined)
int x=255;                                // Declare and initialize x to 255
short s; long l;                          // Usually 16 or 32 bit integer (int may be either)
char c='a';                               // Usually 8 bit character
unsigned char u=255;
signed char s=-1;                         // char might be either
unsigned long x = 0xffffffffL;            // short, int, long are signed
float f; double d;                        // Single or double precision real (never unsigned)
bool b=true;                              // true or false, may also use int (1 or 0)
int a, b, c;                              // Multiple declarations
int a[10];                                // Array of 10 ints (a[0] through a[9])
int a[]={0,1,2};                          // Initialized array (or a[3]={0,1,2}; )
int a[2][2]={{1,2},{4,5}};                // Array of array of ints
char s[]="hello";                         // String (6 elements including '\0')
std::string s = "Hello"                   // Creates string object with value "Hello"
std::string s = R"(Hello World)";         // Creates string object with value "Hello\nWorld"
int* p;                                   // p is a pointer to (address of) int
char* s="hello";                          // s points to unnamed array containing "hello"
void* p=nullptr;                          // Address of untyped memory (nullptr is 0)
int& r=x;                                 // r is a reference to (alias of) int x
enum weekend {SAT,SUN};                   // weekend is a type with values SAT and SUN
enum weekend day;                         // day is a variable of type weekend
enum weekend{SAT=0,SUN=1};                // Explicit representation as int
enum {SAT,SUN} day;                       // Anonymous enum
enum class Color {Red,Blue};              // Color is a strict type with values Red and Blue
Color x = Color::Red;                     // Assign Color x to red
typedef String char*;                     // String s; means char* s;
const int c=3;                            // Constants must be initialized, cannot assign to
const int* p=a;                           // Contents of p (elements of a) are constant
int* const p=a;                           // p (but not contents) are constant
const int* const p=a;                     // Both p and its contents are constant
const int& cr=x;                          // cr cannot be assigned to change x
int8_t,uint8_t,int16_t,
uint16_t,int32_t,uint32_t,
int64_t,uint64_t                          // Fixed length standard types
auto it = m.begin();                      // Declares it to the result of m.begin()
auto const param = config["param"];       // Declares it to the const result
auto& s = singleton::instance();          // Declares it to a reference of the result

πŸ” | More


Storage Classes

int x;                      // Auto (memory exists only while in scope)
static int x;               // Global lifetime even if local scope
extern int x;               // Information only, declared elsewhere

πŸ” | More


Statements

x=y;                        // Every expression is a statement
int x;                      // Declarations are statements
;                           // Empty statement
{                           // A block is a single statement
    int x;                  // Scope of x is from declaration to end of block
}
if (x) a;                   // If x is true (not 0), evaluate a
else if (y) b;              // If not x and y (optional, may be repeated)
else c;                     // If not x and not y (optional)

while (x) a;                // Repeat 0 or more times while x is true

for (x; y; z) a;            // Equivalent to: x; while(y) {a; z;}

for (x : y) a;              // Range-based for loop e.g.
                            // for (auto& x in someList) x.y();

do a; while (x);            // Equivalent to: a; while(x) a; main difference with while loop is that loop is executed once before the condition is checked

switch (x) {                // x must be int
    case X1: a;             // If x == X1 (must be a const), jump here
    case X2: b;             // Else if x == X2, jump here
    default: c;             // Else jump here (optional)
}
break;                      // Jump out of while, do, or for loop, or switch
continue;                   // Jump to bottom of while, do, or for loop
return x;                   // Return x from function to caller
try { a; }
catch (T t) { b; }          // If a throws a T, then jump here
catch (...) { c; }          // If a throws something else, jump here

πŸ” | More


Functions

int f(int x, int y);        // f is a function taking 2 ints and returning int
void f();                   // f is a procedure taking no arguments
void f(int a=0);            // f() is equivalent to f(0)
f();                        // Default return type is int
inline f();                 // Optimize for speed
f() { statements; }         // Function definition (must be global)

T operator+(T x, T y);      // a+b (if type T) calls operator+(a, b); is called "operator overloading"
T operator-(T x);           // -a calls function operator-(a)
T operator++(int);          // postfix ++ or -- (parameter ignored)

extern "C" {void f();}      // f() was compiled in C
  • A function calling itself is known as a recursive function. See here.
int function(int &m) {
  m = 2*m;
  if(m < 20) {
    function(m);
  }
  return m;
}
int main() {
  int a = 2;  // initially
  std::cout << "Now a = " << function(a);
}
// Output: Now a = 32
  • Function parameters and return values may be of any type. A function must either be declared or defined before it is used. It may be declared first and defined later. Every program consists of a set of a set of global variable declarations and a set of function definitions (possibly in separate files), one of which must be:
int main()  { statements... }     // OR
int main(int argc, char* argv[]) { statements... }
  • argv is an array of argc strings from the command line. By convention, main returns status 0 if successful, 1 or higher for errors.

  • Functions with different parameters may have the same name (overloading). Operators except :: . .* ?: may be overloaded. Precedence order is not affected. New operators may not be created.

πŸ” | More


Expression

  • Operators are grouped by precedence, highest first.
  • Unary operators and assignment evaluate right to left. All others are left to right.
  • Precedence does not affect order of evaluation, which is undefined. There are no run time checks for arrays out of bounds, invalid pointers, etc.
T::X                        // Name X defined in class T
N::X                        // Name X defined in namespace N
::X                         // Global name X

t.x                         // Member x of struct or class t
p-> x                       // Member x of struct or class pointed to by p
a[i]                        // i'th element of array a
f(x,y)                      // Call to function f with arguments x and y
T(x,y)                      // Object of class T initialized with x and y
x++                         // Add 1 to x, evaluates to original x (postfix)
x--                         // Subtract 1 from x, evaluates to original x
typeid(x)                   // Type of x
typeid(T)                   // Equals typeid(x) if x is a T
dynamic_cast< T>(x)         // Converts x to a T, checked at run time.
static_cast< T>(x)          // Converts x to a T, not checked
reinterpret_cast< T>(x)     // Interpret bits of x as a T
const_cast< T>(x)           // Converts x to same type T but not const

sizeof x                    // Number of bytes used to represent object x
sizeof(T)                   // Number of bytes to represent type T
++x                         // Add 1 to x, evaluates to new value (prefix)
--x                         // Subtract 1 from x, evaluates to new value
~x                          // Bitwise complement of x
!x                          // true if x is 0, else false (1 or 0 in C)
-x                          // Unary minus
+x                          // Unary plus (default)
&x                          // Address of x
*p                          // Contents of address p (*&x equals x)
new T                       // Address of newly allocated T object
new T(x, y)                 // Address of a T initialized with x, y
new T[x]                    // Address of allocated n-element array of T
delete p                    // Destroy and free object at address p
delete[] p                  // Destroy and free array of objects at p
(T) x                       // Convert x to T (obsolete, use .._cast<T>(x))

x * y                       // Multiply
x / y                       // Divide (integers round toward 0, to avoid round-of to 0; for eg do 1.0/2)
x % y                       // Modulo (result has sign of x)

x + y                       // Add, or \&x[y]
x - y                       // Subtract, or number of elements from *x to *y
x << y                      // x shifted y bits to left (x * pow(2, y))
x >> y                      // x shifted y bits to right (x / pow(2, y))

x < y                       // Less than
x <= y                      // Less than or equal to
x > y                       // Greater than
x >= y                      // Greater than or equal to

x & y                       // Bitwise and (3 & 6 is 2)
x ^ y                       // Bitwise exclusive or (3 ^ 6 is 5)
x | y                       // Bitwise or (3 | 6 is 7)
x && y                      // x and then y (evaluates y only if x (not 0))
x || y                      // x or else y (evaluates y only if x is false (0))
x = y                       // Assign y to x, returns new value of x
x += y                      // x = x + y, also -= *= /= <<= >>= &= |= ^=
x ? y : z                   // y if x is true (nonzero), else z
throw x                     // Throw exception, aborts if not caught
x , y                       // evaluates x and y, returns y (seldom used)

πŸ” | More


Namespaces

namespace N {class T {};}   // Hide name T
N::T t;                     // Use name T in namespace N
using namespace N;          // Make T visible without N::

πŸ” | More


Advanced


Classes

class T {                                               // A new type
private:                                                // Section accessible only to T's member functions
  int p = 2                                             // Defining private variable p
protected:                                              // Also accessible to classes derived from T
public:                                                 // Accessible to all
    int x;                                              // Member data
    void f();                                           // Member function
    void g() {return;}                                  // Inline member function
    void h() const;                                     // Does not modify any data members
    int operator+(int y);                               // t+y means t.operator+(y)
    int operator-();                                    // -t means t.operator-()
    T(): x(1) {}                                        // Constructor with initialization list
    T(const T& t): x(t.x) {}                            // Copy constructor
    T& operator=(const T& t) { x=t.x; return *this;}    // Assignment operator
    int& getp() { return p; }                           // a good way to give access to private variable
    ~T();                                               // Destructor (automatic cleanup routine)
    virtual ~T();                                       // virtual destructor is always a good practice
    explicit T(int a);                                  // Allow t=T(3) but not t=3
    T(float x): T((int)x) {}                            // Delegate constructor to T(int)
    operator int() const { return x; }                  // Allows int(t)
    friend void i();                                    // Global function i() has private access
    friend class U;                                     // Members of class U have private access
    static int y;                                       // Data shared by all T objects
    static void l();                                    // Shared code.  May access y but not x
    class Z {};                                         // Nested class T::Z
    typedef int V;                                      // T::V means int
};

void T::f() {                                           // Code for member function f of class T
    this->x = x;}                                       // this is address of self (means x=x;)
int T::y = 2;                                           // Initialization of static member (required)
T::l();                                                 // Call to static member
T t;                                                    // Create object t implicit call constructor
t.f();                                                  // Call method f on object t

struct T {                                              // Equivalent to: class T { public:
  virtual void i();                                     // May be overridden at run time by derived class
  virtual void g()=0; };                                // Must be overridden (pure virtual)
class U: public T {                                     // Derived class U inherits all members of base T
  public:
  void g(int) override; };                              // Override method g
class V: private T {};                                  // Inherited members of T become private
class W: public T, public U {};                         // Multiple inheritance
class X: public virtual T {};                           // Classes derived from X have base T directly

All classes have a default copy constructor, assignment operator, and destructor, which perform the corresponding operations on each data member and each base class as shown above. There is also a default no-argument constructor (required to create arrays) if the class has no constructors. Constructors, assignment, and destructors do not inherit.

πŸ” | More


Templates

template <class T> T f(T t);                 // Overload f for all types
template <class T> class X {                 // Class with type parameter T
  X(T t); };                                 // A constructor
template <class T> X<T>::X(T t) {}           // Definition of constructor
X<int> x(3);                                 // An object of type "X of int"
template <class T, class U=T, int n=0>       // Template with default parameters

πŸ” | More


Dynamic Memory Management

#include <memory>                            // Include memory (std namespace)
shared_ptr<int> x;                           // Empty shared_ptr to a integer on heap. Uses reference counting for cleaning up objects.
x = make_shared<int>(12);                    // Allocate value 12 on heap
shared_ptr<int> y = x;                       // Copy shared_ptr, implicit changes reference count to 2.
cout << *y;                                  // Dereference y to print '12'
if (y.get() == x.get()) {                    // Raw pointers (here x == y)
    cout << "Same";
}
y.reset();                                   // Eliminate one owner of object
if (y.get() != x.get()) {
    cout << "Different";
}
if (y == nullptr) {                          // Can compare against nullptr (here returns true)
    cout << "Empty";
}
y = make_shared<int>(15);                    // Assign new value
cout << *y;                                  // Dereference x to print '15'
cout << *x;                                  // Dereference x to print '12'
weak_ptr<int> w;                             // Create empty weak pointer
w = y;                                       // w has weak reference to y.
if (shared_ptr<int> s = w.lock()) {          // Has to be copied into a shared_ptr before usage
    cout << *s;
}
unique_ptr<int> z;                           // Create empty unique pointers
unique_ptr<int> q;
z = make_unique<int>(16);                    // Allocate int (16) on heap. Only one reference allowed.
q = move(z);                                 // Move reference from z to q.
if (z == nullptr){
    cout << "Z null";
}
cout << *q;
shared_ptr<B> r;
r = dynamic_pointer_cast<B>(t);             // Converts t to a shared_ptr<B>

πŸ” | More


Standard Template Libraries (1)


Math.h

  • cmath, floating point math
#include <cmath>                    // Include cmath (std namespace)
sin(x); cos(x); tan(x);             // Trig functions, x (double) is in radians
asin(x); acos(x); atan(x);          // Inverses
atan2(y, x);                        // atan(y/x)
sinh(x); cosh(x); tanh(x);          // Hyperbolic sin, cos, tan functions
exp(x); log(x); log10(x);           // e to the x, log base e, log base 10
pow(x, y); sqrt(x);                 // x to the y, square root
ceil(x); floor(x);                  // Round up or down (as a double)
abs(x), fabs(y); fmod(y, z);        // Absolute value for float, y mod z

πŸ” | More


assert.h, cassert

  • Debugging aid
  • In the production build, add -DNDEBUG to compile options so that assert() is not compiled. Note: CMake does this for you. More click here!
#include <cassert>        // Include iostream (std namespace)
assert(e);                // If e is false, print message and abort
#define NDEBUG            // To turn off assertion, add before #include <assert.h>

πŸ” | More


iostream.h

  • iostream (Replaces stdio.h)
#include <iostream>         // Include iostream (std namespace)
cin >> x >> y;              // Read words x and y (any type) from stdin
cout << "x=" << 3 << endl;  // Write line to stdout
cerr << x << y << flush;    // Write to stderr and flush
c = cin.get();              // c = getchar();
cin.get(c);                 // Read char
cin.getline(s, n, '\n');    // Read line into char s[n] to '\n' (default)
if (cin)                    // Good state (not EOF)?
                            // To read/write any type T:

istream& operator>>(istream& i, T& x) {i >> ...; x=...; return i;}
ostream& operator<<(ostream& o, const T& x) {return o << ...;}

πŸ” | More


fstream.h

  • fstream (File I/O works like cin, cout as above)
#include <fstream>          // Include filestream (std namespace)
ifstream f1("filename");    // Open text file for reading
if (f1)                     // Test if open and input available
    f1 >> x;                // Read object from file
f1.get(s);                  // Read char or line
f1.getline(s, n);           // Read line into string s[n]
ofstream f2("filename");    // Open file for writing
if (f2) f2 << x;            // Write to file

πŸ” | More


string

  • Variable sized character array
#include <string>           // Include string (std namespace)
string s1, s2="hello";      // Create strings
s1.size(), s2.size();       // Number of characters: 0, 5
s1 += s2 + ' ' + "world";   // Concatenation
s1 == "hello world"         // Comparison, also <, >, !=, etc.
s1[0];                      // 'h'
s1.substr(m, n);            // Substring of size n starting at s1[m]
s1.c_str();                 // Convert to const char*
s1 = to_string(12.05);      // Converts number to string
getline(cin, s);            // Read line ending in '\n'

πŸ” | More


Standard Template Libraries (2)


utility

  • pair
#include <utility>                  // Include utility (std namespace)
pair<string, int> a("hello", 3);    // A 2-element struct
a.first;                            // "hello"
a.second;                           // 3

πŸ” | More


algorithm

  • A collection of 60 algorithms on sequences with iterators
#include <algorithm>            // Include algorithm (std namespace)
min(x, y); max(x, y);           // Smaller/larger of x, y (any type defining <)
swap(x, y);                     // Exchange values of variables x and y
sort(a, a+n);                   // Sort array a[0]..a[n-1] by <
sort(a.begin(), a.end());       // Sort vector or deque
reverse(a.begin(), a.end());    // Reverse vector or deque

πŸ” | More


chrono

  • Time related library
#include <chrono>                                         // Include chrono
using namespace std::chrono;                              // Use namespace
auto from =                                               // Get current time_point
  high_resolution_clock::now();
// ... do some work
auto to = high_resolution_clock::now();                   // Get current time_point
using ms = duration<float, milliseconds::period>;         // Define ms as floating point duration

cout << duration_cast<ms>(to - from).count() << "ms";     // Compute duration in milliseconds

πŸ” | More


thread

  • Multi-threading library
#include <thread>                                          // Include thread
unsigned c = hardware_concurrency();                       // Hardware threads (or 0 for unknown)
auto lambdaFn = [](){cout << "Hello multithreading";};     // Lambda function used for thread body
thread t(lambdaFn);                                        // Create and run thread with lambda
t.join();                                                  // Wait for t finishes

// --- shared resource example ---
mutex mut;                                                 // Mutex for synchronization
condition_variable cond;                                   // Shared condition variable
const char* sharedMes = nullptr;                           // Shared resource

auto pingPongFn =                                          // thread body (lambda). Print someone else's message
  [&](const char* mes){
    while (true){
      unique_lock<mutex> lock(mut);                        // locks the mutex
      do {
        cond.wait(lock, [&](){                             // wait for condition to be true (unlocks while waiting which allows other threads to modify)
          return sharedMes != mes;                         // statement for when to continue
        });
      } while (sharedMes == mes);                          // prevents spurious wakeup
      cout << sharedMes << endl;
      sharedMes = mes;
      lock.unlock();                                       // no need to have lock on notify
      cond.notify_all();                                   // notify all condition has changed
    }
  };
sharedMes = "ping";
thread t1(pingPongFn, sharedMes);                         // start example with 3 concurrent threads
thread t2(pingPongFn, "pong");
thread t3(pingPongFn, "boing");

πŸ” | More


future

  • thread support library
#include <future>                    // Include future
function<int(int)> fib =             // Create lambda function
  [&](int i){
    if (i <= 1){
      return 1;
    }
    return fib(i-1)
         + fib(i-2);
  };
future<int> fut =                    // result of async function
  async(launch::async, fib, 4);      // start async function in other thread
// do some other work
cout << fut.get();                   // get result of async function. Wait if needed.

πŸ” | More


numeric

  • contains useful algebra functions
#include <numeric>                                        // Include numeric
// For std::accumulate function
#include <vector>                                         // To use a vector
vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};        // Create a vector
int sum = accumulate(v.begin(), v.end(), 0);         // Sum all the vector, we set 0 to start from 0. i.e. init = 0
int sum1 = accumulate(v.begin(), v.end(), 2);        // similar to sum1 = sum + 2
float sum2 = accumulate(v.begin(), v.end(), 2.0);    // Note, to have float, put 2.0 instead of 2. So whole operation is float

πŸ” | More


Standard Data Structure


vector

  • Variable sized array/stack with built in memory allocation
  • Ordered collection of objects of the same type.
#include <vector>                                                          // Include vector (std namespace)
vector<int> a(10);                                                         // a[0]..a[9] are int (default size is 0)
vector<int> b{1,2,3};                                                      // Create vector with values 1,2,3
a.size();                                                                  // Number of elements (10)
a.push_back(3);                                                            // Increase size to 11, a[10]=3
a.back()=4;                                                                // a[10]=4;
a.pop_back();                                                              // Decrease size by 1
a.front();                                                                 // a[0];
a[20]=1;                                                                   // Crash: not bounds checked
a.at(20)=1;                                                                // Like a[20] but throws out_of_range()
for (int& p : a)
  p=0;                                                                     // C++11: Set all elements of a to 0
for (vector<int>::iterator p=a.begin(); p!=a.end(); ++p) {*p=0;}           // C++03: Set all elements of a to 0
vector<int> b(a.begin(), a.end());                                         // b is copy of a
vector<T> c(n, x);                                                         // c[0]..c[n-1] init to x
T d[10]; vector<T> e(d, d+10);                                             // e is initialized from d

πŸ” | More


queue

  • insert from back and delete from front
#include <queue>
queue <int> qsam;       // declare queue object
qsam.push(1);           // inserts element at the end
qsam.push(2);
qsam.size();            // returns the number of elements
qsam.front();           // access the first element
qsam.back();            // access the last element
qsam.pop();             // removes the first element

πŸ” | More


deque

  • double ended queue

deque<T> is like vector<T>, but also supports:

#include <deque>          // Include deque (std namespace)
a.push_front(x);          // Puts x at a[0], shifts elements toward back
a.pop_front();            // Removes a[0], shifts toward front

πŸ” | More


map

  • associative array
  • usually implemented as binary search trees
  • avg. time complexity: O(log n)
#include <map>                           // Include map (std namespace)
map<string, int> a;                      // Map from string to int
a["hello"] = 3;                          // Add or replace element a["hello"]
for (auto& p:a)
    cout << p.first << p.second;         // Prints hello, 3
a.size();                                // Output: 1

πŸ” | More


unordered_map

  • associative array
  • usually implemented as hash table
  • avg. time complexity: O(1)
  • unordered_map is faster than map. See StackExchange. Think before you choose map.
#include <unordered_map>            // Include map (std namespace)
unordered_map<string, int> a;       // Map from string to int
a["hello"] = 3;                     // Add or replace element a["hello"]
for (auto& p:a)
    cout << p.first << p.second;    // Prints hello, 3
a.size();                           // Output: 1
  • Simple example when you want to supply a custom hash function (see cppreference):
#include <functional>              // To use hash
struct hashFunction {
    size_t operator()(const string& s) const {
        return hash<string>()(s);
    }
};

unordered_map<string, int, hashFunction> a;

// But, this is equivalent to the following:
unordered_map<string, int> a; // So, this is just a trivial example.
  • Above, example is a trivial usage of custom hash function. The non-trivial case is when you want to use a STL container as a key in a hash table (i.e. in C++, its called unordered_map). See cppreference for more details.
    • Here is a non-trivial example: custom hash function for array when using unordered_map
template<class T, size_t N>
struct hashFunction {
  size_t operator()(const array<T, N>& a) const {
    size_t h = 0;
    for (auto e : a) {
      // See 2003 - Timothy C. Hoad, Justing Zobel - Methods for identifying versioned and plagiarized documents, section Fingerprint Generation, eq. 1.
      // 0x9e3779b9 is a 32-bit fractional part of golden ratio. See https://softwareengineering.stackexchange.com/a/402543/425163
      h ^= hash<int>{}(e)  + 0x9e3779b9 + (h << 6) + (h >> 2);  // is used in boost::hash_combine. But it's not a good hash function. See https://stackoverflow.com/a/50978188/20915376
    }
    return h;
  }
};

unordered_map<array<int, 2>, int, hashFunction<int, 2>> b;

πŸ” | More


set

  • store unique elements
  • usually implemented as binary search trees
  • avg. time complexity: O(log n))

Any given object can only appear once.

#include <set>                   // Include set (std namespace)
set<int> s;                      // Set of integers
s.insert(123);                   // Add element to set
if (s.find(123) != s.end())      // Search for an element
    s.erase(123);
cout << s.size();                // Number of elements in set

πŸ” | More


unordered_set

  • store unique elements
  • usually implemented as a hash set
  • avg. time complexity: O(1))
#include <unordered_set>          // Include set (std namespace)
unordered_set<int> s;             // Set of integers
s.insert(123);                    // Add element to set
if (s.find(123) != s.end())       // Search for an element
    s.erase(123);
cout << s.size();                 // Number of elements in set

πŸ” | More


pair

  • store two heterogeneous objects as a single unit
  • specific case of a std::tuple with two elements
#include <pair>                      // Include pair
std::pair<int, int> p1;              // one way i.e. default constructor
p1 = std::make_pair(2, 1);           // using std::make_pair
std::pair<float, int> p2(2.5, 1);    // another way i.e. value init
std::pair<float, int> p3(p2);        // another way i.e. copy constructor
p2.first = 4.5;                      // another way of initialization of value
p2.second = 1;                       // We can overwrite the previous value
std::cout << p1.first;               // You can call first element of p1 to print

πŸ” | More


tuple

  • generalization of pair
  • It is a fixed-size collection of values from same or different data types.
#include <tuple>                                     // std::get already in std::tuple
#include <iostream>
std::tuple <char, int, float> mytuple;               // Declaring tuple
mytuple = make_tuple('d', 10, 17.89);                // Assigning values to tuple using make_tuple()
std::cout << std::get<0>(mytuple) << std::endl;      // using std::get() to print values. Output: 'd'
std::get<0>(mytuple) = 'r';                          // using std::get() to change values of tuple

πŸ” | More


Compiler Flags & Options


Search Path & Library Linking

-l <library>               # links to shared library or shared object
-L <library path>          # add search path to shared libraries, directories containing *.so, *.dll, *.dylib depending on the OS platform
-I <include path>          # add search path to header files .h or .hpp
-D <macro>                 # define macro for preprocessor

πŸ” | More


gcc Compiler

-std=<cpp version>         # Specify the C++ standard to use. For example: -std=c++11, -std=c++14, -std=c++17, -std=c++20, -std=gnu++ (which is ISO C++ with GNU extensions), etc.
-o <output filename>       # Specify the output filename. *.o -> Generated on *NIX - Linux, MacOSX … by GCC or Clang. *.obj -> Generated on Windows by MSVC
-c                         # Compiler source(s) to object-code (input to linker). This option is better for incremental compilation when using multiple files.
-lpthread                  # Compile against Posix threads shared library
-shared                    # Builds a shared library. .so or .dylib on U*nix-like Oses. .dll on MS-Windows
-pie                       # Builds a dynamically linked position independent executable
-static-pie                # Builds a statically linked position independent executable
-static-libgfortran        # Link statically againstGNU fortran runtime library
-static-libgcc             # Link statically against GNU C runtime library
-static-libstdc++          # Link statically against GNU C++ runtime library
-heap

πŸ” | More


Optimization

-O0                         # is the default optimization level. It is the least optimized and the slowest, meaning that it is the best for debugging with no optimization.
-O1                         # is the first optimization level. It is the fastest and the least optimized, meaning that it is the best for production. It inline functions, remove dead code, etc.
-O2                         # is the second optimization level. It is faster and more optimized than `-O1`.
-O3                         # is the optimization level 3. Most aggressive optimization but highest level of optimization and speed. Its problem is slower compile time and large binary size, and more function inlining; loop vectorization and SIMD instructions.
-OS                         # is the optimization level for size. Enable `-O2`, but disable some optimizations flags in-order to reduce object-code size.
-Oz                         # is only for CLANG compiler. Optimizes for size even further than `-OS`
-Ofast                      # is the fastest optimization level. It is the same as `-O3` but it enables `-ffast-math` flag. This flag enables unsafe math optimizations, such as reordering floating-point operations and ignoring IEEE 754 floating-point standard. This flag is not recommended for production. Note that it disregards strict standard compliance.
-finline-functions          # Attempt to inline all functions, even if they are not annotated with inlining. Note: inlining trades speeed for increasing of code size.
-mcpu=pentium4              # Tune to Pentium 4 everything about the produced code.
-march=native               # Tune to the current CPU everything about the produced code.
-mtune=native               # Tune to the current CPU only the performance critical parts of the code.

πŸ” | More


Debugging and Profiling

-g                         # Generate debugging information where builds executable has debugging symbols for GDB GNU debugger or LLDB Clang/LLVM debugger. It should only be used during development for debugging builds.
-Og                        # is the optimization level for debugging. Same as `-O0` but it enables `-g` flag. This flag is recommended for debugging. Enables all optimizations that doesnot conflicts with debugging.
-Wall                      # a verbosity option that enable all warnings. W stands for warning. To be specific: -Waddress, -Wcomment, -Wformat, -Wbool-compare, -Wuninitialized, -Wunknown-pragmas, -Wunused-value, ...
-Werror                    # Treat all warnings as errors and stop compilation
-Wextra                         # or just -W. Enables extra flags not enabled by -Wall, such as -Wsign-compare (for C only), -Wtype-limits, -Wuninitialized, ...
-Wpendantic                # Issue all the warnings demanded by strict ISO C and ISO C++ standard, it issues warning whenever there are compiler extensions non compliant with the standard.
-pg                        # Generate profiling information for further processing and measuring performance with gprof program. It should only be used during development for profiling builds.

πŸ” | More


nvcc Compiler

  • NVIDIA CUDA version 11.x supports C++11 and C++14
  • NVIDIA CUDA version 12.x supports C++17
-g -G                      # Generate debugging information for GDB and CUDA-GDB. These must be passed in pair to nvcc.
--disable-warnings         # Disable all warnings. Note that error and warning are different things.

-Xcompiler <CPU flag>      # Pass options to the host compiler. CPU flag needs to be in pair with -Xcompiler. For example: -Xcompiler -O3 -Xcompiler -Wall
-Xcompiler -Wall           # Pass -Wall to the host compiler
-Xcompiler -fopenmp        # Pass -fopenmp to the host compiler and use openmp in the host code

-lcudart                   # Link CUDA runtime library
-lcudadevrt                # Link CUDA device runtime library

-lcusparse                 # Link cuSPARSE library
-lcublas                   # Link cuBLAS library
-lcufft                    # Link cuFFT library
-lcurand                   # Link cuRAND library
-lcusolver                 # Link cuSOLVER library

πŸ” | More


Extra


XY problem

XY problem means “you want to do X, and you think Y is the best way of doing so. Instead of asking about X, you ask about Y.”. This is the case when you have to choose from standard cpp available data structure. Here is the flowchart for this problem:

πŸ” | More


Hash Function

  • Good hash function should:

    • be very fast to compute
    • be bijective to not lose information; it should minimize duplication of output values (collisions)
    • cascade as much and as evenly as possible, i.e. each input bit should flip every output bit with probability 0.5; called avalanche effect in cryptography
    • Read more at Wikipedia, Lecture Note, & StackExchange
  • Types of hash function:

    • Cryptographic hash function aims to be secure against collision or pre-images attacks and that the output appears random, and guarantee a number of security properties.
    • Non-cryptographic hash functions aims only to avoid collisions for input. For example, to put objects into different buckets in a hash table with as few collisions as possible. It’s typically (much) faster than cryptographic hash functions.
  • See the list of hash functions in Wikipedia


Tips and Tricks

std::set<int> s({1,2,3,4});                          // Let's define a set
std::vector new_s(s.begin(), s.end());               // Convert the set to vector container
int first_element = *s.begin();                      // To access the first element of a set "s"
int last_element = new_s.back();                     // Get last element from a vector "new_s"

(unsigned)v;                                         // If v is a non-negative value then, it is safe to cast to unsigned

std::vector<std::tuple<int, int, int>> vec;          // Define a vector of tuple
vec.emplace_back(0, 1, 2);                           // Add element of tuple type in vector

std::ofstream file;                                  // This data type represents the output file stream and is used to create files and to write information to files.
bool writeToAFile = true;
file(writeToAFile ? "filename.txt" : NULL);          // If writeToAFile is true, write to file, else do nothing
                                                     // Instead of NULL, in Linux system, one may like to use "/dev/null" which is a special file that does nothing but it not a good practice because the file size can be increased.

unsigned int x = 2;                                  // x is a non-negative value
std::min(x, 3);                                      // min(x, 3) gives error in compile time
std::min<unsigned int>(x, 3);                        // So, the solution is to explicitly mention the template argument. Then, it will return an unsigned int i.e. 2 in this case.
std::min(x, static_cast<unsigned int>(3));           // Another alternative solution: pass function arguments of same type by casting 3 (default: int) to unsigned int type.


// Extract the file name from a given path
std::string filepath = "spacetimes/conf-4.00-0.02-4-10k-1-torus.dat";   // Let's define a filepath
std::string filename = filepath.substr(filepath.find_last_of("/")+1, filepath.find_last_of(".") - filepath.find_last_of("/") - 1);  // Extract filename from filepath (i.e. conf-4.00-0.02-4-10k-1-torus)

cmake

  • CMake is a cross-platform, open-source, powerful, and easy-to-use tool for building, testing, and shipping software.
cmake -S . -B build                                    # Create cmake build Debug version of the project (i.e. Makefile) where . is the root directory of the project

# More specific command to build Debug version of the project. But both above and below commands are same.
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug

cmake -S . -B build -DCMAKE_BUILD_TYPE=Release         # Create cmake build Release version of the project

cd build && make                                       # To make executable file of your project
# To add OPENMP support
# ---------------------

find_package(OpenMP)
if (OPENMP_FOUND)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
endif()

# To check if your compiler supports OpenMP, use the following command in the terminal:
# echo |cpp -fopenmp -dM |grep -i open

# Turning off assert(). Just in-case, you're worried; add this in CMakeLists.txt
if (NOT CMAKE_BUILD_TYPE MATCHES Debug)
    add_definitions(-DNDEBUG)
endif()

## Or you can use a more convenient and human-readable way
set(release 1)  # Release (production) build
if (release)
    add_definitions(-DNDEBUG)
endif ()

# Good practice to confirm that the external packages are installed. For example:
find_package(Eigen3 CONFIG REQUIRED)
message(STATUS "Found Eigen3 Version: ${Eigen3_VERSION} | Path: ${Eigen3_DIR}")
include_directories(${EIGEN3_INCLUDE_DIR})
#-> Replace Eigen3 by the package name. For example: Spectra_VERSION, Spectra_DIR.

#----------------------------------------------------------------------------------------------------------------------------------------

# For DOXYGEN documentation
#--------------------------

# Build the documentation only in Release mode.
if (CMAKE_BUILD_TYPE MATCHES "^[Rr]elease")

# check if Doxygen is installed
find_package(Doxygen)
if (DOXYGEN_FOUND)
    # set input and output files
    set(DOXYGEN_IN ${CMAKE_CURRENT_SOURCE_DIR}/docs/Doxyfile) # Doxyfile config file is in the /docs folder, change the path accordingly
    set(DOXYGEN_OUT ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)

    # request to configure the file
    configure_file(${DOXYGEN_IN} ${DOXYGEN_OUT} @ONLY)
    message("Doxygen build started!")

    # note the option ALL which allows to build the docs together with the application
    add_custom_target( doc_doxygen ALL
        COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_OUT}
        WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
        COMMENT "Generating API documentation using Doxygen at ${CMAKE_CURRENT_BINARY_DIR}/doc_doxygen"
        VERBATIM )
else (DOXYGEN_FOUND)
  message("Doxygen need to be installed to generate the Doxygen documentation")
endif (DOXYGEN_FOUND)

endif()

# Note in the /docs/Doxyfile file, find the following parameter and add like this:
# OUTPUT_DIRECTORY = @CMAKE_CURRENT_BINARY_DIR@/doc_doxygen/
# INPUT = @CMAKE_CURRENT_SOURCE_DIR@/src/ @CMAKE_CURRENT_SOURCE_DIR@/docs
#----------------------------------------------------------------------------------------------------------------------------------------

πŸ” | More


Permalink at https://www.physicslog.com/cs-notes/cpp

Published on May 3, 2021

Last revised on Dec 7, 2023

References