DeveloperBreeze

Overview

C++ developers often face memory management headaches, especially when working on legacy systems that don’t use C++11 or newer. Smart pointers like std::unique_ptr and std::shared_ptr are powerful, but what if you’re stuck with raw pointers?

In this tutorial, you'll learn:

  • How memory leaks happen.
  • How to structure your code to avoid them.
  • A design pattern to manage dynamic memory safely (RAII without smart pointers).
  • A reusable ScopedPointer class to emulate unique_ptr in old C++.

The Problem: Memory Leaks from Raw Pointers

Consider this code:

void loadData() {
    char* buffer = new char[1024];
    // some processing...
    if (someCondition()) {
        return; // leak!
    }
    delete[] buffer;
}

What’s wrong? If someCondition() returns true, buffer is never deallocated.


Solution 1: Manual try/catch + delete (not scalable)

void loadData() {
    char* buffer = new char[1024];
    try {
        if (someCondition()) {
            throw std::runtime_error("Something went wrong");
        }
        // more code...
    } catch (...) {
        delete[] buffer;
        throw;
    }
    delete[] buffer;
}

Not elegant. Easy to forget or misplace deletes. Let's go better.


Solution 2: Use RAII Even Without Smart Pointers

RAII (Resource Acquisition Is Initialization) is a pattern where resource allocation is tied to object lifetime. When an object goes out of scope, its destructor cleans up.

Let’s build a small ScopedPointer class.


ScopedPointer.h

template <typename T>
class ScopedPointer {
private:
    T* ptr;

public:
    explicit ScopedPointer(T* p = nullptr) : ptr(p) {}

    ~ScopedPointer() {
        delete ptr;
    }

    T& operator*() const { return *ptr; }
    T* operator->() const { return ptr; }
    T* get() const { return ptr; }

    void reset(T* p = nullptr) {
        if (ptr != p) {
            delete ptr;
            ptr = p;
        }
    }

    // Prevent copy
    ScopedPointer(const ScopedPointer&) = delete;
    ScopedPointer& operator=(const ScopedPointer&) = delete;
};

For arrays:

template <typename T>
class ScopedArray {
private:
    T* ptr;

public:
    explicit ScopedArray(T* p = nullptr) : ptr(p) {}

    ~ScopedArray() {
        delete[] ptr;
    }

    T& operator[](int index) const { return ptr[index]; }
    T* get() const { return ptr; }

    void reset(T* p = nullptr) {
        if (ptr != p) {
            delete[] ptr;
            ptr = p;
        }
    }

    // Prevent copy
    ScopedArray(const ScopedArray&) = delete;
    ScopedArray& operator=(const ScopedArray&) = delete;
};

Usage

#include "ScopedPointer.h"

void loadData() {
    ScopedArray<char> buffer(new char[1024]);

    if (someCondition()) {
        return; // no memory leak!
    }

    // buffer is auto-deleted when going out of scope
}

Bonus: Integrating with Legacy C APIs

Some legacy APIs require raw pointers. You can still use get():

void legacyFunction(char* data);

void useLegacyAPI() {
    ScopedArray<char> buffer(new char[512]);
    legacyFunction(buffer.get());
}

Conclusion

Even without smart pointers, you can manage memory safely in C++ using the RAII pattern. This approach:

  • Prevents memory leaks.
  • Simplifies exception handling.
  • Keeps your code clean and maintainable.

In newer projects, always prefer std::unique_ptr and std::shared_ptr. But in legacy systems, RAII with simple wrappers like ScopedPointer can save you.

Continue Reading

Discover more amazing content handpicked just for you

Tutorial

Deep Copy in C++: How to Avoid Shallow Copy Pitfalls

class Deep {
public:
    int* data;

    Deep(int val) {
        data = new int(val);
    }

    // Copy constructor for deep copy
    Deep(const Deep& other) {
        data = new int(*other.data);
    }

    // Assignment operator for deep copy
    Deep& operator=(const Deep& other) {
        if (this != &other) {
            delete data;
            data = new int(*other.data);
        }
        return *this;
    }

    ~Deep() {
        delete data;
    }
};

If your class handles dynamic memory:

Apr 11, 2025
Read More
Tutorial

Implementing a Domain-Specific Language (DSL) with LLVM and C++

Header: Lexer.h

#ifndef DSL_LEXER_H
#define DSL_LEXER_H

#include <string>
#include <vector>

enum class TokenType {
    Number,
    Plus,
    Minus,
    Asterisk,
    Slash,
    LParen,
    RParen,
    EndOfFile,
    Invalid
};

struct Token {
    TokenType type;
    std::string text;
    double value; // Only valid for Number tokens.
};

class Lexer {
public:
    Lexer(const std::string& input);
    Token getNextToken();

private:
    const std::string input;
    size_t pos = 0;
    char currentChar();

    void advance();
    void skipWhitespace();
    Token number();
};

#endif // DSL_LEXER_H

Feb 12, 2025
Read More
Tutorial
csharp

Developing a Real-Time Multiplayer Game with Unity and C#

This script allows the player to move forward and backward using the Vertical axis and rotate using the Horizontal axis. The IsOwner check ensures that only the player who owns the object can control it.

  • Save all your changes and go back to the main scene.
  • Press Play and use the NetworkManagerHUD to start as a Host, Client, or Server.
  • You should be able to control the player object and see it move on both the host and client.

Aug 14, 2024
Read More
Code
csharp

Unity Inventory System using Scriptable Objects

This snippet provides a basic structure for creating an inventory system using scriptable objects in Unity, which allows for easy data management and scalability.

Create a scriptable object for defining item properties.

Aug 12, 2024
Read More
Code
csharp

Unity Player Controller Blueprint

No preview available for this content.

Aug 12, 2024
Read More
Code
csharp

Calculate Sum of Numbers in Array

No preview available for this content.

Jan 26, 2024
Read More

Discussion 0

Please sign in to join the discussion.

No comments yet. Start the discussion!