Home / Forums / Smart Pointers in Practice: std::unique_ptr, std::shared_ptr and std::weak_ptr

UnreliableCode Community

Developer Research, Reverse Engineering & Coding Community

Tutorial

Smart Pointers in Practice: std::unique_ptr, std::shared_ptr and std::weak_ptr

VectorByte
Graphics & DirectX Dev
VIP
Rep: 420
Join Date: Aug 2022
Posts: 39
Thanks: 115
2y ago · May 14, 2024 11:30 AM
#1
Modern C++ emphasizes **RAII (Resource Acquisition Is Initialization)**. In intermediate and production codebases, manual
CODE
new
and
CODE
delete
should be replaced with smart pointers.

1.
CODE
std::unique_ptr<T>
(Zero Overhead Ownership)

- Exclusive ownership model. Cannot be copied, only moved.
- Has zero memory or CPU runtime overhead compared to a raw pointer.
- Always prefer
CPP
std::make_unique<T>()
:

CPP
#include <memory>
#include <iostream>

struct Texture {
    int width, height;
    Texture(int w, int h) : width(w), height(h) {}
    void Bind() { std::cout << "Texture bound: " << width << "x" << height << "
"; }
};

void ProcessTexture() {
    auto tex = std::make_unique<Texture>(1920, 1080);
    tex->Bind();
    // Memory is automatically released when tex goes out of scope!
}


---

2.
CODE
std::shared_ptr<T>
(Reference Counted Ownership)

- Multiple shared pointers can own the same object.
- Maintains an atomic control block tracking reference count (
CODE
use_count
).
- Deletes resource when reference count reaches 0.

CPP
auto sharedTex = std::make_shared<Texture>(512, 512);
std::cout << "Ref count: " << sharedTex.use_count() << "
"; // 1
{
    auto alias = sharedTex;
    std::cout << "Ref count inside scope: " << sharedTex.use_count() << "
"; // 2
}
std::cout << "Ref count after scope: " << sharedTex.use_count() << "
"; // 1


---

3.
CODE
std::weak_ptr<T>
(Breaking Circular References)

- Observes a
CODE
std::shared_ptr
without incrementing the reference count.
- Prevents memory leaks caused by cyclic dependencies (e.g. Node A pointing to Node B, and Node B pointing back to Node A).

CPP
std::weak_ptr<Texture> weakTex = sharedTex;
if (auto locked = weakTex.lock()) { // Safely convert to shared_ptr if object is still alive
    locked->Bind();
} else {
    std::cout << "Texture was destroyed
";
}
VectorByte | DirectX 11/12 Hooking & ImGui Overlays
Quote
Math is the language of game engines.
The following users thanked VectorByte for this post:
SecurityAudit
AppSec & Code Auditor
MEMBER
Rep: 135
Join Date: Jan 2025
Posts: 28
Thanks: 29
2y ago · May 14, 2024 2:10 PM
#2
Using
CPP
std::make_unique
and
CPP
std::make_shared
is also exception-safe because it prevents memory leaks if another argument in a function call throws before the pointer constructor finishes.

Additionally,
CPP
std::make_shared
allocates the control block and user object in a single contiguous heap allocation, saving cache misses!
SecurityAudit | Secure C++ Architecture & Boundary Auditing
DarkLogic
Game Logic & SDK Developer
MEMBER
Rep: 180
Join Date: Jun 2024
Posts: 28
Thanks: 41
2y ago · May 14, 2024 5:35 PM
#3
Custom deleters with
CODE
std::unique_ptr
are also fantastic for C API cleanup:
CPP
std::unique_ptr<FILE, decltype(&fclose)> filePtr(fopen("data.bin", "rb"), &fclose);

Automatically closes the file handle regardless of how the function exits!
DarkLogic | Virtual method tables & SDKs