---
# System prepended metadata

title: 'Books : Optimized C++ & 21st Century C & Understanding and Using C Pointers & Effective Modern C++'
tags: [Performance Engineering & Algorithm Design with C++]

---

# Books : Optimized C++ & 21st Century C & Understanding and Using C Pointers & Effective Modern C++

> Reference \:
> * Optimized C++
> https://www.tenlong.com.tw/products/9789864762651
> * 21st Century C\: C Tips from the New School
> https://www.tenlong.com.tw/products/9789865021368?list_name=srh
> * Understanding and Using C Pointers
> https://www.tenlong.com.tw/products/9789862769409?list_name=rd
> * Effective Modern C++
> https://www.tenlong.com.tw/products/9789863478669?list_name=trs-t

*This four books are reference books when I learning and developing C\/C++ Programming. This note only include notes and extra materials I used as I reviewing these books. Note that books page numbers will be referenced as the tranditional chinese translated version which are the ones that I have hard copy of.*

# Optimized C++ by Kurt Guntheroth

> * Optimized C++
> https://www.tenlong.com.tw/products/9789864762651

## Variable Storage Durations

> Reference \: Chapter 6 page 108

* Static Storage Duration \:
    * Fix address assigned in compile time.
    * Create storage space for static variable do not have cost in runtime.
* Thread-local Storage Duration
    * `thread-local`
    * Created when a thread is created and destroyed with the thread.
    * All threads have a indepandent copy of the variable.
:::info
:information_source: **thread_local 變數**
* C++11 thread_local 用法
https://murphypei.github.io/blog/2020/02/thread-local
* thread_local 變數 *Google C++ Style Guide 繁體中文版*
https://www.slmt.tw/google-cpp-style-guide-zh-tw/scoping/thread-local-variables.html
:::
* Automatic Storage Duration
    * Store in funtion call stack.
    * No runtime cost.
    * Limited space.
    * Nested function calls can cause stack overflow.
* Dynamic Storage Duration
    * Call memory manager.
    * Address assigned in runtime.
    * Created and destroyed according to the programmer.

## Dynamic Memory Allocations

:::success
:bulb: **Cost of `shared_ptr`**

A `shared_ptr` will have a reference count that will use `atomic` operation. This make `shared_ptr` work in multi-threading construct but definitely cause more.
:::

:::success
:bulb: **Use of `std::ref`**

https://shengyu7697.github.io/std-ref/
:::

# 21st Century C

> * 21st Century C\: C Tips from the New School
> https://www.tenlong.com.tw/products/9789865021368?list_name=srh

:::info
:information_source: **`cc` in Linux**

https://stackoverflow.com/questions/1516609/difference-between-cc-gcc-and-g

```bash
cc -> /usr/bin/gcc # Output from EPYC Server with Ubuntu 22.04
```
:::

## C Macros

### Good Practices

* Add parentesis to every input even constant numbers.
```cpp
#define double(x) (2 * (x))
```
* Pitfalls
```cpp
#define max(a, b) ((a) > (b) ? (a) : (b))
    
// ...
    
int m = max(x, y++); // cause error
int m = ((x) > (y++) ? (x) : (y++)) // this is why
```
* Add Brackets `{}`
```cpp
#define doubleincrement(a, b) \
    (a)++;                    \
    (b)++;

int x = 2, y = 0;
if (x > y)
    doubleincrement(x, y); // cause error

if (x > y)
    (x)++;
(y)++;                    // this is why

#define doubleincrement(a, b) { \
    (a)++;                      \
    (b)++;                      \
}
```
* Check result by using `gcc -E source.c | less`


## TODO

# Understanding and Using C Pointers

> * Understanding and Using C Pointers
> https://www.tenlong.com.tw/products/9789862769409?list_name=rd

## Chapter \#1 \: Basic

### `NULL` in C

Notice that all of the information provide here is only for `NULL` in C, which is not nessacery can be mapped to `NULL` in C++. However, in C++, `NULL` should be replaiced with `nullptr`

> * Understanding and Using C Pointers **Page 11**
> https://www.tenlong.com.tw/products/9789862769409?list_name=rd

As a programmer, the value of null should not be concerned. A `NULL` macro can be defined as `#define NULL ((void*)0)`. Notice that a uninitialized pointer can point to anywhere in the memory but a pointer initialized as null will not point to any place in the memory.


### `void` in C

* A `void` pointer can be sized and will have memory alignment as `char`.
* `void` pointer will not be equal to any other pointers. The only exception is when two void pointers are asigned as `NULL`.


### `intptr_t` & `uintptr_t`

> Reference \: 
> https://stackoverflow.com/a/6328676

First, `intptr_t` is only for data pointers \(not functions\) and is not guaranteed to exist.

Then, no, you shouldn't use it for the purpose of printing. The %p is for that. You just have to cast your pointer to `(void*)` and there you go.

It is also no good for arithmetic / accessing individual bytes. Cast to `(unsigned char*)` instead.

`intptr_t` is really for the rare occasions that you have to interpret pointers as integers \(which they really aren't\). Don't that if you mustn't.

## Chapter \#2 \: Dynamic Memory Allocation

:::warning
Initializing `static` or global variables cannot use function calls.
:::

:::warning
Good practice is to assign freed memory to `NULL` in C and `nullptr` in C++.
:::

### Memory Allocation Functions

* `malloc`
* `realloc` \: New size can be smaller and rest of the memory will be released or bigger and will try to allocate memory contiguously if, falled to do so, will allocate memory in new location and copy original data to it.
* `calloc` \: Will fill in `0b0` and is slower than `malloc`
* `free`

### Boehm-Demers-Weiser Garbage Collector

> Reference \:
> * Github Repo
> https://github.com/ivmai/bdwgc

## Chapter \#3 \: Pointer and Functions

### Function Pointer

> Reference \:
> * https://www.geeksforgeeks.org/function-pointer-in-cpp/
> * https://www.scaler.com/topics/c/function-pointer-in-c/

Basically include the function return value and parameters to create a function pointer. Can be used to change involking function without branching.

```cpp
void (*foo)();

// return_value_type (pointer_name)(params);
```

:::success
Naming convention \: All function pointer should prefix with a `fptr`.
:::

**Example from Book Page 75**
```cpp
int (*fptr1)(int);

int square (int num) {
    return num * num;
}

fptr1 = square;
fptr1(5); // call a function with function with funciton pointer
```

## Chapter \#4 Pointer and Arrays

*Notice that we can only use raw array in this plain C.*

Nothing special in this chapter that is new to me.

:::success
:bulb: **Using `restrict`**

`restrict` mark a pointer without alias and make compiler possibly create more efficient program. **Using it in function is recommanded**.
:::

# Effective Modern C++ 

Notice that this book only include `C++11` \& `C++14`. I mainly use `C++17` or `C++20` \(*Depand on the Linux Kernel and OS version default*\) now. However, this book is definitely worth reading.

## Chapter 1 \: Type Inference

I don't use template much, thus I only have limited understanding of the advanced topic about template.

### Item \#1 \: Understand Template Type Reference

```cpp
template <typename T>
void func(ParaType param);

// example
template <typename T>
void func(const T& param);

int x = 0;
func(x);

// T will be int and ParamType will be const int&
```

There are the following three possible situations and two special case for raw array and function pointer. **Refer to the book page 9 \~ 15.**

* `ParamType` is a pointer or reference type
* `ParamType` is a universal reference
* `ParamType` is not a pointer nor a reference

### Item \#2 \: `auto` Type inference

Same as template type inference with T as `auto` itself and `ParamType` as type specifier.

Notice that using `auto` with `{}` to define a variable will be considered as `std::initializer_list`.

:::warning
Unlike what the book suggest, in my opinion, I will only use `auto` on something that its type is very obvious to provide readibility.
:::

### Item \#3 \: `decltype` TODO

### Item \#4 \: Use IDE to Read the Infered Type

## Chapter 2 \: `auto`

Understanding `auto`. However, as described in Item \#2, my opinion still stands for myself \(03\/06\/2025\)

## Chapter 3 \: Toward Modern C++

### Item \#7 \: Initialize with `()` or `{}`

Basically, use `{}` for initialization and remember that `T Var {}` and `T Var = {}` is the same thing; however, for convinient purpose, we should use `T Var {}`.

**Pros**
* Uniform
* No marrowing conversion ish
* Not affect by `C++ most vexing parse`

:::info
:information_source: **C++ Most Vexing Parse**

In C\+\+, whatever can be read as function declaration will be see as function declaration.

```cpp
Widget w2(); // see as function declaration not calling the constructor without parameter

Widget w2{}; // this will call the constructor without parameter
```
:::

**Cons**

* Using `{}` will choose the constructor with `std::initializer_list` even its not a good match. Only when the parameters cannot be convert to the `std::initializer_list` will the compiler look for other choice.
```cpp
std::vector<int> v1(10, 20); // 10 elements each with 20 as value

std::vector<int> v2{10, 20}; // a vector with 2 elements 10 and 20
```
* **fricking** templates

### Item \#8 \: Use `nullptr` to replace `0` and `NULL`

No need to explain here. I guess.

### Item \#9 \: Use `using` not `typedef`

Basically, just do it and all pros; no cons.

Notice that use `c++14` version of `<type_traits>` ([Reference](https://en.cppreference.com/w/cpp/header/type_traits)) It's all about **template** which I use rarely and mostly naively \(2025\/02\/25\).

```cpp
std::remove_const<T>::type;// c++11
std::remove_const_t<T>; //c++14 and later
```

### Item \#10 \: Use Scoped `enum`

* Limited scope

```cpp
enum Color {black, white, red};

auto white = false; // error; white is declared

enum class Color {black, white, red}; // in Color scope

auto white = false; // ok;
```

* No auto casting

### Item \#11 : `delete` function not is not required

Not just automatically created constructor, there are some functions, if you want people not able to them, we can delete them. Similar to what I did in [CUDA_AI_Framework](https://github.com/Chen-KaiTsai/CUDA_AI_Framework/blob/main/framework.cuh). Calling these deleted functions will cause compile error, which is way better than error in runtime.

### Item \#12 \: Using `override`

`virtual` functions should be marked as `override` in derived classes. This `override` require functions to abey the following rules.

* Base class function should be mark as `virtual`
* Base class function and derived class function should have same name.
* As above, the function sign should be the same.
* `const` should be set the same
* return value and exception should handle in the same way.

Notice that doing this will not add any function to your code; however, the biggest advantage is error happened in compile time not in runtime.

:::success
:bulb: **Member function Qualifier**

A good article can be found here.

https://hackmd.io/@yW7HKRexRASTmH3kBDXQpQ/HyogR_X9q
:::

### Item \#13 \: Replace `iterator` with `const_iterator` when possible

The simplest example is replace `var.begin()` and `var.end()` with `var.cbegin()` and `var.cend()`

### Item \#14 \: Mark function that will not have exception with `noexcept`

TODO

### Item \#15 \: Use `constexpr` as much as Possible

Mark a variable as `constexpr` will make sure its value is available and even calculated in compile time. Therefore, this is best for a constant variable with a constant value.

For `constexpr` functions, refer to [this post](https://learn.microsoft.com/zh-tw/cpp/cpp/constexpr-cpp?view=msvc-170) from Microsoft which provide most some new update for newer version of C\+\+

### Item \#16 \: Make `const` member function thread-safe

Read the book for the example.

Basically, a `const` member function with `mutable` variables still can make changes. Therefore, obviously, a synchronization is needed to prevent data race.

### Item \#17 \: Special Member Functions

* **Default Constructor** \: Only auto-generated when there is no other constructor declared.
* **Deconstructor** \: deconstructor is default to `noexcept`
* **Copy Assign Operator** \: `Obj& operator=(const Obj&)` as above, only generated when costume copy assign operator is not defined.
* **Move Constructor \& Move Assign Operator** \: Only generated when customed copy constructor, move constructor and deconstructor are not defined. If the move constructor is defined, move assign operator will not be auto-generated. These two functions should both be defined when needed.

**Refere to the book for more detail. These section work only as a reminder.**

:::success
:bulb: **List of Special Member Functions**

https://en.wikipedia.org/wiki/Special_member_functions
:::

## Chapter 4 \: Smart Pointers

*I already use a lot of `unique_ptr` in my projects. However, `shared_ptr` is much more complex and I desire to have deeper understanding of it.*

### Item \#18 \: `unique_ptr`

### Item \#19 \: `shared_ptr`

`std::shared_ptr` use reference count. When count to `0`, the `shared_ptr` will call the deconstructor of the pointed object. Constructor of `std::shared_ptr` will increase the reference count and deconstructor will decrease it. Additionally, moving `shared_ptr` will not take any action on reference count.

**Performance Consideration**

* `std::shared_ptr` is two times bigger than raw pointer since it contain a counter
* Reference counter is **dynamically allocated**
* Reference counter use `atomic`

**structure of `shared_ptr`**

![image](https://hackmd.io/_uploads/BJXCY_Viyl.png =x200)

**When will a Control Block Created**

* `std::make_shared` will create a control block for a object, which of course has no control block.
* from `std::unique_ptr` to `std::shared_ptr`
* use raw pointer to create a `std::shared_ptr`
    * This will casue a possible multiple control block for a raw pointer and causing undefined behavior \(delte twise\)

**Using `this` on a `std::shared_ptr`**

`this` is a raw pointer which will create a control block when used to create a `shared_ptr` and an possible undefined behavior.

**The solution** \: use a based class `std::enable_shared_from_this<T>`

```cpp
class Widget: public std::enable_shared_from_this<Widget> {
    ...
}

void Widget::process() {
    shared_from_this();
}
```

:::info
:information_source: **The Curiously Recurring Template Pattern**

Definitely recommand to check the authors personal blog [Heresy](https://kheresy.wordpress.com/).

https://viml.nchc.org.tw/curiously-recurring-template-pattern/
:::

**`std::shared_ptr` does NOT Support Array**

There is no `std::shared_ptr<T[]>`. Please use `vector`, `array` for raw array.

### Item \#20 \: Use `std::weak_ptr` to replace `std::shared_ptr` that can be danggled

:::info
:information_source: **Access `std::weak_ptr`**

https://stackoverflow.com/a/37680502

**Summary**

* `wp.expired()` will check and return if a `weak_ptr` is expired. However, before you do things further after checking, under multi-thread program, a not expired `weak_ptr` can be expired. Basically, doing this is not thread-safe.
* `wp.lock()` is an atomic operation, which return a `null` when the `wp` is expired and a `std::shared_ptr` if not expired.
:::

**Use Case of `std::weak_ptr`**

![image](https://hackmd.io/_uploads/rku42vBsJl.png)

If the pointer from A to B and B to A are both `std::shared_ptr`, even if the C is not pointed to B, A and B will reference each other and causing the reference count of both `std::shared_ptr` to be `1`. Using `std::weak_ptr` cna prevent this to happen, since it will not increase A's reference count.

:::success
> Reference \: Book Page 126

The used case of `std::weak_ptr` includes caching, observer and prevnet `std::shared_ptr` from danggling.
:::

### Item \#21 \: Use `std::make_unique` and `std::make_shared` to prevent using `new` directly

### Item \#22 \: TODO

## Chapter 5 \: Rvalue References, Move Semantics, and Perfect Forwarding

> Reference \:
> * 潮．C++11 | Universal Reference, Rvalue Reference, Move Semantics
> https://tjsw.medium.com/潮-c-11-universal-reference-rvalue-reference-move-semantics-1ea29f8cabdc

All the parameters are always `lvalue` even an `rvalue` reference type parameter is still `lvalue`. In the following function, `w` is a `rvalue` reference to `Widget`; however, `w` itself is still a `lvalue`. \(Note that the tranditional chinese translation has error here\)

`void f(Widget&& w);`

### Item \#23 \: Understand `std::move` and `std::forward`

* `std::move` will unconditionally cast the parameter to a `rvalue`
    * the naming of `std::move` is more like \: Assigning an object as a source for moving.
    * If we want to move an object, don't declare the parameter as `const`. The `const` object cannot be moved and will use copy silently instead. *See book page 146*
    * The only thing gurranteed by the `std::move` is that we will get a `rvalue`.
* `std::forward` only cast the parameter when certain condition is met.
```cpp
template<typename T>
void logAndProcess(T&& param)
{
    auto now = std::chrono::system_clock::now();
    makeLogEntry("Calling 'process'", now);
    process(std::forward<T>(param));
}
```
A simple way to understand it is that `param` is a function paramter and will be always be `lvalue`. \(*it has a name*\) `std::forward` will only need to cast `param` to `rvalue` only when the universal reference is called with an `rvalue`.

### Item \#24 \: Distinguish universal references from rvalue references

**Universal Reference**

```cpp
// context #1
template<typename T>
void f(T&& param);

// context #2
auto&& var2 = var1;
```

Notice that both of them require to have type deduction; therefore we can say that if a `T&&` does not have type deduction, it will be `rvalue` reference.

Additionally, the format is very limited to `T&&`.
```cpp
template<typename T>

void f(std::vector<T>&& param); // this is rvalue reference
```

Even for a `const`.
```cpp
template<typename T>
void f(const T&& param); // this is rvalue reference
```

### Item \#25 \: Use `std::move` on rvalue references, `std::forward` on universal references

### Item \#26 \: Do not overload Universal Reference

### Item \#27

### Item \#28 \: Reference Collapsing

> Reference \:
> * 潮．C++11 | Universal Reference, Rvalue Reference, Move Semantics
> https://tjsw.medium.com/潮-c-11-universal-reference-rvalue-reference-move-semantics-1ea29f8cabdc

### Item \#29 \: Assume that move operations are not present, not cheap, and not used

* No move operations
* Move not faster
* Move not usable
* Source object is `lvalue`

### Item \#30

## Chapter 6 \: Lambda

> Reference \:
> * 潮．C++14 | Generic Lambda：無腦寫不用管型別！？還能特技表演
> https://tjsw.medium.com/潮-c-14-generic-lambda-無腦寫不用管型別-還能特技表演-54c3668734a9

Lambda expression \: `[]() {};`.
*closure* is a runtime object that created with a lambda expression.

### Item \#31 \: Prevent Using Default Capture Mode

* **by-reference**
If a closure's lifespan is exceeds the local variable or parameter, the reference in the closure will be dangle.

```cpp
[&]() {};
[&var]() {}; // mark the refered variable
```
* **by-value**

```cpp
[=]() {}; // However, you still have to worry about pointers
```

### Item \#32 \: Use Init capture to move objects into closures

```cpp
auto func = [var = /*statement for initialization*/]() {};
```

### Item \#33 \: Use `decltype` on `auto&&` parameters to `std::forward` them

**TODO**

### Item \#34 \: Prefer lambdas to `std::bind`

Don't need to go futher since I don't have any experience using `std::bind`.

## Chapter 7 \: Concurrency API

:::info
:information_source: **My other Post about C++ Concurrency**

* Books : The Art of ... Series?
https://hackmd.io/@Erebustsai/S1sguFsJkg
* Book : Parallel and High Performance Computing
https://hackmd.io/@Erebustsai/rJfAI5w2R
:::

### Item \#35 \: Prefer Task-based Programming to Thread-based

```cpp
{ // thread-based
    int doAsyncWork();
    std::thread t(doAsyncWork);
}

{ // task-based
    auto fut = std::async(doAsyncWork);
}
```

* Using `std::async` can work with functions with return value.
* Using `std::async` can obtain the exception threw, but `std::thread` cannot. The program called with `std::thread` will be terminated with `std::terminate` when throw a exception.
* Using `std::async` can prevent oversubscription.

### Item \#36 \: Specify `std::launch::async` if Asynchronicity is Essential

The default launch policy of `std::async` is `std::launch::async|std::launch::deferred` and this brings the following issues \:

with `auto fut = std::async(f);`

* Cannot predict f is asynchronize with t
* Cannot predict f is runs on the same thread as the thread running `fut.get()` or `fut.wait()`.
* Cannot predict f is actually runs at all.

:::warning
:warning: `thread_local` will be a big issue if not sure `std::async` will be `std::launch::deferred` or `std::launch::async`.
:::

### Item \#37 \: Make Sure `std::thread` is Unjoinable on all Paths

Unjoinable Includes \:
* Default constructed `std::thread`
* `std::thread` that has been moved from
* `std::thread` that has been `join`
* `std::thread` that has been `detach`

### Item \#38 \: Be aware of varying thread handle destructor behavior

![image](https://hackmd.io/_uploads/B1p-rwKiye.png)

The result of the callee cannnot be stored in Callee itself since it will be destroied when funtion exit. The caller cannot store it as well, since `std::future` can be used to create `std::shared_future`. `std::shared_future` might still create multiple copies even when the original `future` is cleared and the result should be kept till the last reference to the `future` is cleared.

The place that store the result is called *shared state*, which is usually on heap.

The behavior of `std::future` destructor is depend on the state of the *shared state*.

The *shared state* created by `std::async` will live until the **last** `future` is deconstructed.

### Item \#39 \: Consider using `void future` as a one time communication event

**Issue with Using Conditional Variables**

```cpp
std::condition_variable cv;
std::mutex m;

cv.notify_one();

{
    cv.wait(lk, []{ /*check if event really happened*/ });
}
```

* A task that has not reaching `wait` will be hanged since it miss the wake event.
* `wait` will not consider Spurious Wakeup
* **The thread that is being woke up need to be able to check if the event really happened.**

:::info
:information_source: **Spurious Wakeup**

* 什麼是spurious wakeups（虛假喚醒）
https://blog.csdn.net/Tornado1102/article/details/76158390
* C++ Condition Variable by [Lei Mao](https://github.com/leimao)
https://leimao.github.io/blog/CPP-Condition-Variable/
:::

**Using Atomic Boolean as Flag**

This basically is spin lock.

**Better Way**

```cpp
std::condition_variable cv;
std::mutex m;

bool flag = false;

{
    std::lock_guard<std::mutexx> g(m);
    flag = true;
}
cv.notify_one();

{
    std::unique_lock<std::mutex> lk(m);
    cv.wait(lk, []{ return flag; });
}
```

**If Only Need One Time**

Use `std::shared_future`

### Item \#40 \: `std::atmic` for Parallel; `volatile` for Special Memory

**What is `volatile`?**

* 【C/C\+\+面試必備】詳解C\/C++中`volatile`關鍵字
https://blog.csdn.net/qq_44918090/article/details/125749268

Basically, this require the compiler to not use value that will be in the register but to access memory everytime this variable is accessed.

## Chapter 8 \: Tweaks

### Item \#41 \: Consider Pass by Value for Copyable Parameters that ara cheap to move and always copied

**Overloading for lvalue and rvalue**

```cpp
class Widget {
public:
    void addName(const std::string& newName) {
        names.push_back(newName);
    }
    void addName(const std::string&& newName) {
        names.push_back(std::move(newName));
    }
    
    ...
}
```

In the above example provided by the book, a `lvalue` will be copy to `names` vector and a `rvalue` will be moved.

**Pass by Value**

```cpp
class Widget {
public:
    void addName(std::string newName) { // pass by value will accept both rvalue and lvalue
        names.push_back(std::move(newName));
    }
}
```

One important thing the book point out is that in `C++98`, `addName` will be using copy constructor. However, in `C++11`, `addName()` will use **copy constructor** for `lvalue` and **move constructor** with `rvalue`.

The difference between the above two solution is that \: 
* **Overloading** will have **one copy for `lvalue`** and **one move for `rvaule`**.
* **Pass by Value** will have **one copy and one move for `lvalue`** and **two move for `rvalue`**

### Item \#42 \: Consider Emplacement instead of Insertion

[**C++11 使用 emplace 取代 push_back 和 insert**](https://viml.nchc.org.tw/cpp11-emplace/)
