Cheatsheets

Personal collection of cheatsheets.

C++

C++ is a general-purpose programming language created as an extension of the C programming language.

Index

Libraries

A library is a collection of resources used by programs. These resources may include code, data, templates, documentation, etc.

There are 2 types of libraries, static and dynamic.

When linking is performed during the creation of an executable or an object file, it is known as static linking (early binding). In this case, the linking is usually done by a linker, but may also be done by the compiler.

When linking is performed while a program is being loaded (load time) or executed (runtime), it is known as dynamic linking (late binding).

Dynamic libraries have 2 types of linking.

Null

std::nullptr

std::nullptr (C++11) is the null pointer literal.

std::nullptr_t

std::nullptr_t (C++11) is the type of the null pointer literal nullptr.

Pointers

std::unique_ptr

std::unique_ptr (C++11) is a smart pointer that owns and manages another object (heap-allocated memory) via a pointer and subsequently disposes of that object when the unique_ptr goes out of scope.

#include <memory>

class Foo
{
public:
    void Bar(){}
};

void Process(const Foo& foo)
{
    // ...
}

void Run()
{
    std::unique_ptr<Foo> foo = std::make_unique<Foo>();

    // Call a method on the object.
    foo->Bar();

    // Pass the reference to a function.
    Process(*foo);

    // Deleted automatically when function block goes out of scope.
}

int main(int argc, char** argv)
{
    Run();
    return 0; 
}

std::shared_ptr

std::shared_ptr (C++11) is a smart pointer that retains shared ownership of an object through a pointer. Several shared_ptr objects may own the same object. The object is destroyed and its memory deallocated when the last remaining shared_ptr owning the object is destroyed.

#include <memory>

class Foo
{
public:
    void Bar(){}
};

void Process1(std::shared_ptr<Foo> foo)
{
    // ...
}

void Process2(std::shared_ptr<Foo> foo)
{
    // ...
}

int main(int argc, char** argv)
{
    std::shared_ptr<Foo> foo = std::make_shared<Foo>();

    Process1(p);
    Process2(p);

    return 0;
}

std::weak_ptr

std::weak_ptr (C++11) is a smart pointer that holds a non-owning (weak) reference to an object that is managed by std::shared_ptr. It must be converted to std::shared_ptr in order to access the referenced object.

Concurrency

std::thread

std::thread (C++11) provides a standard way to write multithreaded programs accross all platforms abstracting the code from other threading APIs like POSIX pthreads or Windows threads.

#include <iostream>
#include <thread>

void Task1()
{
    for (int i = 0; i < 100; i++)
    {
        std::cout << "(Task, 1)";
        std::cout << " (Thread ID, " << std::this_thread::get_id() << ")";
        std::cout << " (Loop, " << i << ")";
        std::cout << std::endl;
    }
}

void Task2()
{
    for (int i = 0; i < 100; i++)
    {
        std::cout << "(Task, 2)";
        std::cout << " (Thread ID, " << std::this_thread::get_id() << ")";
        std::cout << " (Loop, " << i << ")";
        std::cout << std::endl;
    }
}

int main(int argc, char** argv)
{
    std::thread worker1(Task1);
    std::thread worker2(Task2);
    
    worker1.join();
    worker2.join();
    
    return 0;
}

std::async

std::async (C++11) provides a way to run a function asynchronously (potentially in a separate thread) and returns a std::future that will eventually hold the result of that function call.

Policies:

#include <future>
#include <iostream>
#include <thread>

void Task(std::string name, int count)
{
    for (int i = 0; i < count; i++)
    {
        std::cout << "(Task, " << name << ")";
        std::cout << " (Thread ID, " << std::this_thread::get_id() << ")";
        std::cout << " (Loop, " << i << ")";
        std::cout << std::endl;
    }
}

int main(int argc, char** argv)
{
    std::future<void> future1 = std::async(std::launch::async, Task, "Task1", 100);
    std::future<void> future2 = std::async(std::launch::async, Task, "Task2", 200);

    future1.get();
    future2.get();

    return 0;
}

Comparing thread-based programming (std::thread) and task-based programming (std::async).

State-of-the-art thread schedulers employ system-wide thread pools to avoid oversubscription, and they improve load balancing across hardware cores through workstealing algorithms. The C++ Standard does not require the use of thread pools or work-stealing, and, to be honest, there are some technical aspects of the C++11 concurrency specification that make it more difficult to employ them than we’d like. Nevertheless, some vendors take advantage of this technology in their Standard Library implementations, and it’s reasonable to expect that progress will continue in this area. If you take a task-based approach to your concurrent programming, you automatically reap the benefits of such technology as it becomes more widespread. If, on the other hand, you program directly with std::threads, you assume the burden of dealing with thread exhaustion, oversubscription, and load balancing yourself, not to mention how your solutions to these problems mesh with the solutions implemented in programs running in other processes on the same machine.

std::future

std::future (C++11) provides a way to access the result of asynchronous operations.

std::promise

std::promise (C++11) provides a way to store a value or an exception that is later acquired asynchronously via a std::future created by the std::promise.

References