# RAII and Smart Pointers — C++

Source: https://www.skillbyai.com/en/cpp/m-raii

> Manage resources with RAII and choose between unique_ptr, shared_ptr and weak_ptr.

## Resource Acquisition Is Initialisation

**RAII** is the most important idiom in C++: tie a resource's lifetime to an object's lifetime. The constructor **acquires** the resource (memory, a file, a lock, a socket) and the destructor **releases** it. Because destructors run automatically when objects go out of scope, including during exception unwinding, resources can never leak. Standard examples: `std::vector` (memory), `std::fstream` (files), `std::lock_guard` (mutexes) and **smart pointers** for heap objects. **`std::unique_ptr<T>`** expresses **exclusive ownership**: exactly one owner, zero overhead compared with a raw pointer, movable but not copyable; create it with **`std::make_unique`**. **`std::shared_ptr<T>`** expresses **shared ownership** with a **reference count**; the object is destroyed when the last owner goes away; create with **`std::make_shared`**. It costs more (atomic counting, a control block), so use it only when ownership is genuinely shared. **`std::weak_ptr<T>`** observes a shared object without owning it, breaking **reference cycles** (for example a child pointing back to its parent) that would otherwise leak.

## Choosing a smart pointer

unique_ptr by default, shared_ptr when ownership is shared, weak_ptr to break cycles.

```cpp
#include <memory>
#include <string>
#include <vector>

struct Engine { int hp; };

struct Car {
    std::unique_ptr<Engine> engine = std::make_unique<Engine>(Engine{120});  // exclusive owner
};

struct Node {
    std::string name;
    std::vector<std::shared_ptr<Node>> children;   // parent owns children
    std::weak_ptr<Node> parent;                    // child observes parent: no cycle
};

int main() {
    Car a;
    Car b = std::move(a);          // ownership of the engine moves to b; a.engine is now null

    auto root = std::make_shared<Node>(Node{"root"});
    auto leaf = std::make_shared<Node>(Node{"leaf"});
    leaf->parent = root;
    root->children.push_back(leaf);

    if (auto p = leaf->parent.lock()) {          // temporary shared_ptr if parent still alive
        // use p->name
    }
}   // everything is released automatically here
```

## unique_ptr first

Start with `std::unique_ptr`. Switch to `std::shared_ptr` only when several parts of the program genuinely co-own an object and none can be designated the single owner.

**Quiz:** Which smart pointer expresses exclusive, single ownership with no reference-counting overhead?

- [ ] std::shared_ptr
- [ ] std::weak_ptr
- [x] std::unique_ptr
- [ ] A raw pointer

*Answer:* std::unique_ptr. unique_ptr has exactly one owner and is as cheap as a raw pointer.
