# Overview
> Smart pointers is wrapper class of normal pointer, which automatically release itself (by calling destructor) once **it goes out of scope**. Scope here might be inside a function.
Hold on. Excuse me, what? We should not take it like this. Normal classes' destructors are also called once getting out of scope. Smart pointers like `shared_ptr, unique_ptr, etc.` are just part of them.
**The essence is that smart pointers are intended to be used as local variables** (in most cases, like class members or function variables). And similar to any other class variable allocated this way - which lifetime is **tied** to some sort of scope, the destructor will be called when it goes out of scope. This follows the principle of RAII.
## RAII
*They say RAII is probably the best feature of C++.*
> Resource Acquisition Is Initialization (RAII) is a C++ programming technique which **binds the life cycle of a resource** to **the lifetime of an object**. The **resource** here might be heap memory, thread of execution, open socket, open file, locked mutex, disk space, data base connection - which must be acquired before use.
To put it simply, the **lifetime** of an object refers to the period of time between object's construction and destruction. **Lifecycle** of a resource refer to the period of time between resource's **allocation** and **de-allocation** (free it, sort of). This is how it goes:
> Allocate -> Object Constructor -> ... -> Object Destructor -> De-allocate
**Why: Safer memory usage, better performance without any garbage collection overhead**π Without this, class destructor must implement memory release operation itself, and that tends to leave bugs due to bad coding practices.
**Standard lib:** `std::vector`, `std::string`, smart pointers and `std::lock_guard`, `std::unique_lock`, etc. to manage mutexes.
Read more: [https://en.cppreference.com/w/cpp/language/raii](https://en.cppreference.com/w/cpp/language/raii)
<!-- ### Stack unwinding (C++ only) -->
## What is scope anyway
How do compiler define "scope"? How does it know when a smart pointer goes out of scope and insert some code to call the smart pointer destructor at that place?
> The same way everything in C++ knows it's gone out of scope - it reaches the end of the surrounding pair of {}s (or, if it is a member variable of another struct, the destructor of the parent will call the destructors of all child elements).
```cpp!=
#include <memory>
struct foo {
std::unique_ptr<int> p;
};
int main() {
std::unique_ptr<int> a;
{
std::unique_ptr<int> b;
} // b now goes out of scope and is destructed
{
foo f;
} // f now goes out of scope, meaning both f and f::p are destructed
} // a now goes out of scope and is destructed
```
### What if we attempt to call the destructor?
Compiler automatically inserts code to call to object destructor. Now we would like to make a call to destructor right before the end of function. It would result in calling destructor twice.
**If the destructor is responsible for releasing some sort of memory, memory corruption would happen.**
# Smart Pointers
Now get back to smart pointers. Once the destructor is called, the wrapped object's destructor is also called.
- `~unique_ptr()` immediately calls the object's destructor.
- `~shared_ptr()` only decreases the `use_count` (reference count) by one until it reaches `-1` and then call the wrapped object's destructor later on.
## `std::shared_ptr<T>` internals
> Several shared_ptr instances can share the management of an object's lifetime **through a common control block**. The managed object is deleted when the last owning shared_ptr is destroyed (or is made to point to another object). Memory management by `shared_ptr` is **deterministic** because the timing of a managed object's destruction is predictable and **in the developer's control**.
Well, but how is it implemented? A `shared_ptr` contains 2 pointers (hence size is 16 in `x86-64`).

In this section, we'd like to focus on the second one - the pointer to **control block**.
The first pointer is the raw pointer of the object being wrapped - returned by `get()` method. More more information, read [Pwning in C++](https://hackmd.io/@trhoanglan04/pwningCpp) (TiαΊΏng Viα»t).
An array of `shared_ptr<IOSymbol>` looks like this in memory:

Notice that:
- The `vtable` address are the same for all `share_ptr<IOSymbol>` instances (0x555555568860 and 0x5555555686d0). However, the control block addresses are different **heap address** due to the default `std::allocator`. The allocator can be specified.
```
pwndbg> p (std::shared_ptr<IOSymbol>) *0x7ffff7a28058
$4 = {
<std::__shared_ptr<IOSymbol, (__gnu_cxx::_Lock_policy)2>> = {
<std::__shared_ptr_access<IOSymbol, (__gnu_cxx::_Lock_policy)2, false, false>> = {<No data fields>},
members of std::__shared_ptr<IOSymbol, (__gnu_cxx::_Lock_policy)2>:
_M_ptr = 0x7ffff7fa7050,
_M_refcount = {
_M_pi = 0x5555555e7090
}
}, <No data fields>}
```
- This is how the control block looks like:
```
pwndbg> telescope 0x5555555e7250 3
00:0000β 0x5555555e7250 ββΈ 0x5555555686d0 (vtable for std::_Sp_counted_ptr<IOSymbol*, (__gnu_cxx::_Lock_policy)2>+16) ββΈ 0x55555555b162 (std::_Sp_counted_ptr<IOSymbol*, (__gnu_cxx::_Lock_policy)2>::~_Sp_counted_ptr()) ββ endbr64
01:0008β 0x5555555e7258 ββ 0x100000002
02:0010β 0x5555555e7260 ββΈ 0x7ffff7fa73d0 ββΈ 0x555555568828 (vtable for IOSymbol+16) ββΈ 0x5555555576fa (IOBytes::compare(ArrayTemplate<unsigned char> const&)) ββ endbr64
```
What is that `0x100000002`? Weak count and ref count right?
### Operators
- Assign: [std::shared_ptr<T>::operator=](https://en.cppreference.com/w/cpp/memory/shared_ptr/operator%3D)
If the current pointer points to an existing object before the assignment, that existing object would be destroyed and the new object being assigned's `share_cnt` (reference count) is increased.
- Swap: [std::shared_ptr<T>::swap](https://en.cppreference.com/w/cpp/memory/shared_ptr/swap)
## `std::weak_ptr`
# Pwn it π
# Rust
# Summary
# References
- [Reddit: how_does_a_smart_pointer_know_when_its_gone_out/](https://www.reddit.com/r/cpp_questions/comments/ecmzat/how_does_a_smart_pointer_know_when_its_gone_out/)
- [shared_ptr - basics and internals with examples](https://www.nextptr.com/tutorial/ta1358374985/shared_ptr-basics-and-internals-with-examples)