RoadMap notes 3 Flashcards

Idioms, standards, debuggers, compilers, build systems, packafe managers, libraries

1
Q

RAII (Resource Acquisition Is Initalization)

A

popular idiom in C++ that focuses on using the object’s life cycle to manage resources. It encourages binding the resource lifetime to the scope of a corresponding object so that it’s automatically acquired when an object is created and released when the object is destroyed. This helps in simplifying the code, avoiding leaks and managing resources efficiently.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

example of using RAII to manage resources, specifically a dynamically allocated array:

A

class ManagedArray {
public:
ManagedArray(size_t size) : size_(size), data_(new int[size]) {
}

~ManagedArray() {
    delete[] data_;
}

// Access function
int& operator [](size_t i) {
    return data_[i];
}

private:
size_t size_;
int* data_;
};
Usages:

{
ManagedArray arr(10);
arr[0] = 42;

// No need to explicitly free memory, it will be automatically released when arr goes out of scope. }
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

RAII, Another common use case is managing a mutex lock:

A

class Lock {
public:
Lock(std::mutex& mtx) : mutex_(mtx) {
mutex_.lock();
}

~Lock() {
    mutex_.unlock();
}

private:
std::mutex& mutex_;
};
Usages:

std::mutex some_mutex;

void protected_function() {
Lock lock(some_mutex);

// Do some work that must be synchronized

// No need to explicitly unlock the mutex, it will be automatically unlocked when lock goes out of scope. }
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

Pimpl Idiom (pointer-to-implementation)

A

idiom, also known as a private class data, compiler firewall, or handle classes, is a technique used in C++ to hide the implementation details of a class by using a forward declaration to a private structure or class, keeping the public interface of the class clean, and reducing compile-time dependencies.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

PimpI idiom example

A

class MyClass
{
public:
MyClass();
~MyClass();
void some_method();

private:
MyClass_Impl *pimpl; // pointer to the implementation
};

class MyClass_Impl // the actual implementation
{
public:
void some_method()
{
std::cout &laquo_space;“Implementation method called!” &laquo_space;std::endl;
}
};

MyClass::MyClass() : pimpl(new MyClass_Impl()) {} // constructor

MyClass::~MyClass() { delete pimpl; } // destructor

void MyClass::some_method()
{
pimpl->some_method(); // delegation to the implementation
}

all the public methods of MyClass will delegate the calls to the corresponding methods of MyClass_Impl. By doing this, you can hide the details of class implementation, reduce the compile-time dependencies, and ease the maintenance of your code.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

CRTP (Curiously Recurring Template Pattern)

A

idiom that involves a class template being derived from its own specialization. This pattern allows for the creation of static polymorphism, which differs from regular runtime polymorphism that relies on virtual functions and inheritance.

CRTP is usually employed when you want to customize certain behavior in the base class without adding the overhead of a virtual function call. In short, CRTP can be used for achieving compile-time polymorphism without the runtime performance cost.

template <typename>
class Base {
public:
void interface() {
static_cast<Derived*>(this)->implementation();
}</typename>

void implementation() {
    std::cout << "Default implementation in Base" << std::endl;
} };

class Derived1 : public Base<Derived1> {
public:
void implementation() {
std::cout << "Custom implementation in Derived1" << std::endl;
}
};</Derived1>

class Derived2 : public Base<Derived2> {
// No custom implementation, so Base::implementation will be used.
};</Derived2>

the Base class is a template that takes a single type parameter. Derived1 and Derived2 are derived from their respective specialization of Base. CRTP is employed to allow custom implementations of the implementation() function in derived classes while providing a default behavior in the Base class. The interface() function in the Base class is a template for the derived class’s behavior and calls the corresponding implementation() function based on the static type.

This pattern enables you to override certain behavior in derived classes with additional functionality, all while avoiding the overhead of virtual function calls and, in turn, achieving a higher degree of efficiency at runtime.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

Non-copyable idiom

A

C++ design pattern that prevents objects from being copied or assigned. It’s usually applied to classes that manage resources, like file handles or network sockets, where copying the object could cause issues like resource leaks or double deletions.

To make a class non-copyable, you need to delete the copy constructor and the copy assignment operator. This can be done explicitly in the class declaration, making it clear to other programmers that copying is not allowed.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

Apply the non-copyable idiom to a class

A

lass NonCopyable {
public:
NonCopyable() = default;
~NonCopyable() = default;

// Delete the copy constructor
NonCopyable(const NonCopyable&) = delete;

// Delete the copy assignment operator
NonCopyable& operator=(const NonCopyable&) = delete;
};
To use the idiom, simply inherit from the NonCopyable class:

class MyClass : private NonCopyable {
// MyClass is now non-copyable
};

This ensures that any attempt to copy or assign objects of MyClass will result in a compilation error, thus preventing unwanted behavior.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

Erase-remove idiom

A

common C++ technique to efficiently remove elements from a container, particularly from standard sequence containers like std::vector, std::list, and std::deque. It leverages the standard library algorithms std::remove (or std::remove_if) and the member function erase().

The idiom consists of two steps:

std::remove (or std::remove_if) moves the elements to be removed towards the end of the container and returns an iterator pointing to the first element to remove.
container.erase() removes the elements from the container using the iterator obtained in the previous step.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

Erase-remove idiom example

A

std::vector<int> numbers = {1, 3, 2, 4, 3, 5, 3};</int>

// Remove all occurrences of 3 from the vector.
numbers.erase(std::remove(numbers.begin(), numbers.end(), 3), numbers.end());

for (int number : numbers) {
    std::cout << number << " ";
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

Copy-swap

A

C++ idiom that leverages the copy constructor and swap function to create an assignment operator. It follows a simple, yet powerful paradigm: create a temporary copy of the right-hand side object, and swap its contents with the left-hand side object.

Here’s a brief summary:

Copy: Create a local copy of the right-hand side object. This step leverages the copy constructor, providing exception safety and code reuse.
Swap: Swap the contents of the left-hand side object with the temporary copy. This step typically involves swapping internal pointers or resources, without needing to copy the full contents again.
Destruction: Destroy the temporary copy. This happens upon the exit of the assignment operator.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

class String {
// … rest of the class …

String(const String& other);

void swap(String& other) {
    using std::swap; // for arguments-dependent lookup (ADL)
    swap(size_, other.size_);
    swap(buffer_, other.buffer_);
}

String& operator=(String other) {
    swap(other);
    return *this;
} };
A

Using the copy-swap idiom:

The right-hand side object is copied when passed by value to the assignment operator.
The left-hand side object’s contents are swapped with the temporary copy.
The temporary copy is destroyed, releasing any resources that were previously held by the left-hand side object.
This approach simplifies the implementation and provides strong exception safety, while reusing the copy constructor and destructor code.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

Copy-Write Idiom

A

include <memory></memory>

sometimes called the Copy-on-Write (CoW) or “lazy copying” idiom, is a technique used in programming to minimize the overhead of copying large objects. It helps in reducing the number of actual copy operations by using shared references to objects and only copying the data when it’s required for modification.

class MyString {
public:
MyString(const std::string &str) : data(std::make_shared<std::string>(str)) {}

// Use the same shared data for copying.
MyString(const MyString &other) : data(other.data) { 
    std::cout << "Copied using the Copy-Write idiom." << std::endl;
}

// Make a copy only if we want to modify the data.
void write(const std::string &str) {
    // Check if there's more than one reference.
    if(!data.unique()) {
        data = std::make_shared<std::string>(*data);
        std::cout << "Copy is actually made for writing." << std::endl;
    }
    *data = str;
}

private:
std::shared_ptr<std::string> data;
};

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

C++11 and C++14

A

C++11 The C++11 standard, also known as C++0x, was officially released in September 2011. It introduced several new language features and improvements, including:

Auto: Allows compiler to infer the variable type based on its initializing expression.

auto integer = 42; // integer is of int type
auto floating = 3.14; // floating is of double type
Range-Based for Loop: Provides foreach-like semantics for iterating through a container or array.

std::vector<int> numbers {1, 2, 3, 4};
for (int number : numbers) {
std::cout << number << std::endl;
}
Lambda Functions: Anonymous functions that allow the creation of function objects more easily.</int>

auto add = -> int { return a + b; };
int sum = add(42, 13); // sum is equal to 55
nullptr: A new keyword to represent null pointers, more type-safe than using a literal ‘0’ or “NULL”.

int *ptr = nullptr;
Thread Support Library: Provides a standard way to work with threads and synchronize data access across threads.

std::thread t( { std::cout &laquo_space;“Hello from another thread\n”; });
t.join();
C++14 The C++14 standard was officially released in December 2014 as a small extension over C++11, focusing more on fine-tuning language features and fixing issues. Some of the new features introduced:

Generic Lambdas: Allows lambda function parameters to be declared with ‘auto’ type placeholders.

auto add = { return a + b; };
auto sum_i = add(42, 13); // Still works with integers
auto sum_f = add(3.14, 2.72); // Now works with doubles too
Binary Literals: Allow you to input integers as binary literals for better readability.

int b = 0b110101; // Decimal value is 53
decltype(auto): Deduces the type of variable to match that of the expression it is initialized with.

auto func = { return a * b; };
decltype(auto) result = func(5, 3.14); // decltype(auto) deduces to “double”
Variable Templates: Allows you to define variables with template parameters.

template <typename>
constexpr T pi = T(3.1415926535897932385);
float r = pi<float>; // Instantiated as a float
double d = pi<double>; // Instantiated as a double</double></float></typename>

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

C++17

A

C++17, also known as C++1z, is the version of the C++ programming language published in December 2017. It builds upon the previous standard, C++14, and adds various new features and enhancements to improve the language’s expressiveness, performance, and usability.

Key Features:
If-init-statement: Introduces a new syntax for writing conditions with scope inside if and switch statements.
if(auto it = map.find(key); it != map.end())
{
// Use it
}
Structured Binding Declarations: Simplify the process of unpacking a tuple, pair, or other aggregate types.
map<string, int> data;
auto [iter, success] = data.emplace(“example”, 42);
Inline variables: Enables inline keyword for variables and allows single definition of global and class static variables in header files.
inline int globalVar = 0;
Folds expressions: Introduce fold expressions for variadic templates.
template <typename...>
auto sum(Ts... ts)
{
return (ts + ...);
}
constexpr if statement: Allows conditional compilation during compile time.
template <typename>
auto get_value(T t)
{
if constexpr (std::is_pointer_v<T>)
{
return *t;
}
else
{
return t;
}
}
Improved lambda expression: Allows lambda to capture a single object without changing its type or constness.
auto func = [x = std::move(obj)] { /* use x */ };
Standard file system library: std::filesystem as a standardized way to manipulate paths, directories, and files.</T></typename></typename...>

New Standard Library additions: <string_view> (non-owning string reference), <any> (type-safe discrimination union), <optional> (optional value wrapper), <variant> (type-safe sum type), and <memory_resource> (library for polymorphic allocators).</memory_resource></variant></optional></any></string_view>

Parallel Algorithms: Adds support for parallel execution of Standard Library algorithms.

This is a brief summary of the key features of C++17; it includes more features and library updates. For a complete list, you can refer to the full list of C++17 features and changes.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

Concepts

A

a way to enforce specific requirements on template parameters, allowing you to write more expressive and understandable code. They improve the error messages when using templates and ensure that the template parameters fulfill specific criteria.

template <typename>
concept Addable = requires (T a, T b) {
{ a + b } -> std::same_as<T>;
};</T></typename>

template <Addable>
T add(T a, T b) {
return a + b;
}</Addable>

17
Q

Ranges

A

include <algorithm></algorithm>

provide a new way to work with sequences of values, enhancing the power and expressiveness of the Standard Library algorithms. The range-based algorithms make it easier and more convenient to work with sequences.

#include <iostream>
#include <ranges>
#include <vector></vector></ranges></iostream>

int main() {
std::vector<int> numbers = { 1, 2, 3, 4, 5 };</int>

auto even_numbers = numbers | std::views::filter([](int n) { return n % 2 == 0; });

for (int n : even_numbers) {
    std::cout << n << ' ';
} }
18
Q

Coroutines

A

include <coroutine></coroutine>

a new way to write asynchronous and concurrent code with improved readability. They allow functions to be suspended and resumed, enabling you to write more efficient, non-blocking code.

#include <iostream>
#include <future></future></iostream>

std::future<int> async_value(int value) {
co_await std::chrono::seconds(1);
co_return value * 2;
}</int>

int main() {
auto result = async_value(42);
std::cout &laquo_space;“Result: “ &laquo_space;result.get() &laquo_space;std::endl;
}

19
Q

Both constexpr and consteval are related to compile-time evaluation. Functions marked with constexpr can be executed at compile-time or runtime, while functions marked with consteval can only be executed at compile-time.

A

constexpr int add(int a, int b) {
return a + b;
}

consteval int square(int x) {
return x * x;
}

int main() {
constexpr int result1 = add(3, 4);
// evaluated at compile-time
int result2 = add(5, 6);
// evaluated at runtime
constexpr int result3 = square(7);
// evaluated at compile-time
}

20
Q

Constexpr enhancements

A

constexpr support is extended with additional features, such as constexpr dynamic allocations, constexpr try-catch blocks, and constexpr lambdas.

Example:

struct Point {
constexpr Point(int x, int y): x_{x}, y_{y} {}
int x_, y_;
};

constexpr auto create_points() {
Point points[3]{};

for (int i = 0; i < 3; ++i) {
    points[i] = Point{i, i * i};
}

return points; }

constexpr auto points = create_points();

21
Q

Thread support for multithreading programming

A

include <thread></thread>

void my_function() {
// thread function body
}

int main() {
std::thread t(my_function);
t.join();
return 0;
}

22
Q

Compilation stage 1:
Preprocessing

A

include <iostream></iostream>

The first stage is the preprocessing of the source code. Preprocessors modify the source code before the actual compilation process. They handle directives that start with a # (hash) symbol, like #include, #define, and #if. In this stage, included header files are expanded, macros are replaced, and conditional compilation statements are processed.

Code Example:

#define PI 3.14

int main() {
std::cout &laquo_space;“The value of PI is: “ &laquo_space;PI &laquo_space;std::endl;
return 0;
}

23
Q

Compilation stage 2:
Compilation

A

The second stage is the actual compilation of the preprocessed source code. The compiler translates the modified source code into an intermediate representation, usually specific to the target processor architecture. This step also involves performing syntax checking, semantic analysis, and producing error messages for any issues encountered in the source code.

Code Example:

int main() {
int a = 10;
int b = 20;
int sum = a + b;
return 0;
}

24
Q

Compilation stage 3:
Assembly

A

converting the compiler’s intermediate representation into assembly language. This stage generates assembly code using mnemonics and syntax that is specific to the target processor architecture. Assemblers then convert this assembly code into object code (machine code).

Code Example (x86 Assembly):

mov eax, 10
mov ebx, 20
add eax, ebx

25
Q

Compilation stage 4:
Linking

A

final stage is the linking of the object code with the necessary libraries and other object files. In this stage, the linker merges multiple object files and libraries, resolves external references from other modules or libraries, allocates memory addresses for functions and variables, and generates an executable file that can be run on the target platform.

Code Example (linking objects and libraries):

$ g++ main.o -o main -lm