Agent Skills: Memory Management Skill

>

memory-managementmemory-optimizationsystem-resourcesperformance-tuning
memoryID: pluginagentmarketplace/custom-plugin-cpp/memory-management

Skill Files

Browse the full folder contents for memory-management.

Download Skill

Loading file tree…

skills/memory-management/SKILL.md

Skill Metadata

Name
memory-management
Description
>

Memory Management Skill

Production-Grade Learning Skill | Safe Resource Handling

Master C++ memory management for safe, efficient, and leak-free code.


Core Principles

The Golden Rule: RAII

Resource Acquisition Is Initialization

// ─────────────────────────────────────────────────────
// RAII wrapper for file handles
// ─────────────────────────────────────────────────────
class FileHandle {
    FILE* handle_{nullptr};

public:
    explicit FileHandle(const char* path, const char* mode)
        : handle_(fopen(path, mode))
    {
        if (!handle_) {
            throw std::runtime_error("Failed to open file");
        }
    }

    ~FileHandle() {
        if (handle_) fclose(handle_);
    }

    // Non-copyable
    FileHandle(const FileHandle&) = delete;
    FileHandle& operator=(const FileHandle&) = delete;

    // Movable
    FileHandle(FileHandle&& other) noexcept
        : handle_(std::exchange(other.handle_, nullptr)) {}

    FileHandle& operator=(FileHandle&& other) noexcept {
        if (this != &other) {
            if (handle_) fclose(handle_);
            handle_ = std::exchange(other.handle_, nullptr);
        }
        return *this;
    }

    FILE* get() const { return handle_; }
};

// Usage: automatic cleanup guaranteed
void processFile(const char* path) {
    FileHandle file(path, "r");  // Acquired
    // ... use file ...
}  // Automatically closed, even if exception thrown

Smart Pointers

Ownership Hierarchy

┌─────────────────────────────────────────────────────────────────┐
│  std::unique_ptr  │  Exclusive ownership (default choice)       │
│  std::shared_ptr  │  Shared ownership (reference counted)       │
│  std::weak_ptr    │  Non-owning observer (breaks cycles)        │
└─────────────────────────────────────────────────────────────────┘

unique_ptr (Prefer This)

// Creation (ALWAYS use make_unique)
auto widget = std::make_unique<Widget>(arg1, arg2);

// Array version
auto arr = std::make_unique<int[]>(100);

// Custom deleter
auto file = std::unique_ptr<FILE, decltype(&fclose)>(
    fopen("data.txt", "r"), &fclose
);

// Transfer ownership
void takeOwnership(std::unique_ptr<Widget> w);
takeOwnership(std::move(widget));  // Explicit move required

shared_ptr (Use When Truly Needed)

// Creation
auto shared = std::make_shared<Resource>();  // Single allocation!

// Copy = increment reference count
auto copy = shared;  // ref_count: 2

// Custom deleter
auto custom = std::shared_ptr<Database>(
    new Database(),
    [](Database* db) {
        db->close();
        delete db;
    }
);

weak_ptr (Break Cycles)

class Node {
public:
    std::shared_ptr<Node> next;
    std::weak_ptr<Node> prev;  // Weak to prevent cycle
};

// Safe access through lock()
void useWeakPtr(std::weak_ptr<Resource> weak) {
    if (auto shared = weak.lock()) {  // Returns shared_ptr or nullptr
        shared->doSomething();
    }
}

Memory Issues & Solutions

Quick Reference

| Problem | Detection | Solution | |---------|-----------|----------| | Memory leak | Valgrind, ASan | Use smart pointers | | Dangling pointer | ASan | weak_ptr, proper lifetime | | Double free | ASan | unique_ptr ownership | | Buffer overflow | ASan | std::vector, std::span | | Use after free | ASan | RAII, smart pointers |

Detecting Leaks

# Valgrind (runtime)
valgrind --leak-check=full --show-leak-kinds=all ./program

# AddressSanitizer (compile-time instrumentation)
g++ -fsanitize=address -fno-omit-frame-pointer -g program.cpp

Common Patterns

// ❌ BAD: Raw pointer ownership unclear
Widget* createWidget() {
    return new Widget();  // Who deletes this?
}

// ✅ GOOD: Ownership explicit
std::unique_ptr<Widget> createWidget() {
    return std::make_unique<Widget>();
}

// ❌ BAD: Exception unsafe
void process() {
    Resource* r = new Resource();
    doSomething();  // May throw!
    delete r;       // Never reached if exception
}

// ✅ GOOD: Exception safe
void process() {
    auto r = std::make_unique<Resource>();
    doSomething();  // Even if throws, r is deleted
}

Custom Allocators

Pool Allocator

template<typename T, size_t BlockSize = 4096>
class PoolAllocator {
    struct Block {
        std::array<std::byte, sizeof(T)> data;
        Block* next;
    };

    Block* freeList_{nullptr};
    std::vector<std::unique_ptr<Block[]>> blocks_;

public:
    T* allocate() {
        if (!freeList_) {
            allocateBlock();
        }
        Block* block = freeList_;
        freeList_ = block->next;
        return reinterpret_cast<T*>(&block->data);
    }

    void deallocate(T* ptr) {
        Block* block = reinterpret_cast<Block*>(ptr);
        block->next = freeList_;
        freeList_ = block;
    }

private:
    void allocateBlock() {
        constexpr size_t count = BlockSize / sizeof(Block);
        auto newBlocks = std::make_unique<Block[]>(count);

        for (size_t i = 0; i < count - 1; ++i) {
            newBlocks[i].next = &newBlocks[i + 1];
        }
        newBlocks[count - 1].next = freeList_;
        freeList_ = &newBlocks[0];

        blocks_.push_back(std::move(newBlocks));
    }
};

Troubleshooting

Decision Tree

Memory issue?
├── Leak suspected
│   ├── Run Valgrind → Shows "definitely lost"
│   ├── Check for raw `new` → Replace with make_unique
│   └── Check cyclic references → Use weak_ptr
├── Crash/Corruption
│   ├── Segfault at nullptr → Add null checks
│   ├── Double free → Ensure single owner (unique_ptr)
│   └── Use after free → Check object lifetime
└── Performance
    ├── Too many allocations → Use pool allocator
    ├── Fragmentation → Use arena allocator
    └── False sharing → Align to cache line

Unit Test Template

#include <gtest/gtest.h>
#include <memory>

TEST(SmartPointerTest, UniquePtrOwnership) {
    auto ptr = std::make_unique<int>(42);
    EXPECT_NE(ptr, nullptr);
    EXPECT_EQ(*ptr, 42);

    auto ptr2 = std::move(ptr);
    EXPECT_EQ(ptr, nullptr);  // Ownership transferred
    EXPECT_EQ(*ptr2, 42);
}

TEST(SmartPointerTest, SharedPtrRefCount) {
    auto shared1 = std::make_shared<int>(100);
    EXPECT_EQ(shared1.use_count(), 1);

    auto shared2 = shared1;
    EXPECT_EQ(shared1.use_count(), 2);
}

TEST(SmartPointerTest, WeakPtrExpired) {
    std::weak_ptr<int> weak;
    {
        auto shared = std::make_shared<int>(42);
        weak = shared;
        EXPECT_FALSE(weak.expired());
    }
    EXPECT_TRUE(weak.expired());
}

C++ Plugin v3.0.0 - Production-Grade Learning Skill