Fundamentals 29 min read

Mastering C++ Memory: When to Use new/delete vs malloc/free

This article explains the fundamental differences between C's malloc/free and C++'s new/delete, covering their underlying mechanisms, proper usage patterns, common pitfalls, error‑handling strategies, and best‑practice recommendations such as smart pointers and memory‑pool techniques.

Deepin Linux
Deepin Linux
Deepin Linux
Mastering C++ Memory: When to Use new/delete vs malloc/free

1. Exploring malloc and free

1.1 Basic usage

In C, malloc allocates a raw memory block and returns a void* that must be cast to the desired pointer type; free releases the block back to the system.

#include <stdio.h>
#include <stdlib.h>

int main() {
    int* ptr = (int*)malloc(sizeof(int));
    if (ptr == NULL) {
        printf("Memory allocation failed
");
        return 1;
    }
    *ptr = 10;
    printf("Value in allocated memory: %d
", *ptr);
    free(ptr);
    return 0;
}

1.2 Underlying mechanism

On Linux, malloc is implemented by glibc, which first tries to satisfy requests from an internal memory pool; if the pool lacks space it falls back to system calls brk (for small allocations) or mmap (for large allocations).

1.3 Pitfalls and common traps

Always check the return value of malloc for NULL, set freed pointers to NULL to avoid dangling references, avoid memory leaks by freeing every allocation, and never free the same block twice.

int* ptr = (int*)malloc(100 * sizeof(int));
// Forgetting NULL check leads to crash if allocation fails
*ptr = 10;

int* p = (int*)malloc(sizeof(int));
free(p);
// Using p after free is undefined behavior
*p = 20;

void leak() {
    int* p = (int*)malloc(sizeof(int));
    // missing free -> memory leak
}

int* q = (int*)malloc(sizeof(int));
free(q);
free(q); // double free – undefined behavior

2. The unique power of new and delete

2.1 Basic operation

In C++, new allocates memory (usually via operator new) and then automatically calls the object's constructor; delete calls the destructor before releasing the memory via operator delete.

#include <iostream>

class MyClass {
public:
    MyClass() { std::cout << "Constructor called" << std::endl; }
    ~MyClass() { std::cout << "Destructor called" << std::endl; }
};

int main() {
    MyClass* obj = new MyClass;
    delete obj;
    return 0;
}

2.2 Construction and destruction

When new Person("Alice", 25) is executed, memory is allocated, then the Person constructor initializes name and age. Deleting the object first runs the destructor, releasing any resources, then frees the memory.

class Person {
public:
    std::string name;
    int age;
    Person(const std::string& n, int a) : name(n), age(a) {
        std::cout << "Constructor: " << name << ", " << age << std::endl;
    }
    ~Person() {
        std::cout << "Destructor: " << name << ", " << age << std::endl;
    }
};

2.3 Different forms of new

Ordinary new throws std::bad_alloc on failure; new (std::nothrow) returns NULL instead; placement new constructs an object in pre‑allocated memory.

// ordinary new with exception handling
try {
    int* p = new int(10);
    delete p;
} catch (const std::bad_alloc& e) {
    std::cerr << "Allocation failed: " << e.what() << std::endl;
}

// nothrow new
int* p = new (std::nothrow) int(10);
if (!p) { std::cerr << "Allocation failed" << std::endl; }
else { delete p; }

// placement new
char buffer[sizeof(MyClass)];
MyClass* obj = new (buffer) MyClass; // constructs in buffer
obj->~MyClass(); // manual destruction, no free needed

3. Deep comparison of the two approaches

3.1 Allocation method

malloc

requires manual size calculation and returns a generic pointer; new deduces the size from the type and returns a correctly typed pointer, making code safer.

3.2 Initialization and cleanup

malloc

leaves memory uninitialized; you must manually set values. new runs constructors for objects and zero‑initializes fundamental types when appropriate. free never calls destructors, while delete always does.

3.3 Error handling

malloc

signals failure by returning NULL; the programmer must check it. new signals failure by throwing std::bad_alloc, which can be caught with C++ exception handling.

3.4 Memory release and destructors

free

simply returns the block to the system; no destructors are run, so resources owned by objects are not released. delete first runs the destructor, then frees the memory, preventing leaks for class types.

4. Practical application scenarios

4.1 C projects

Dynamic allocation of an array of Student structures using malloc and releasing it with free demonstrates typical C‑style memory management.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct {
    char name[50];
    int age;
    float score;
} Student;

int main() {
    int n;
    printf("Enter number of students: ");
    scanf("%d", &n);
    Student* students = (Student*)malloc(n * sizeof(Student));
    if (!students) { printf("Allocation failed
"); return 1; }
    // fill and use students ...
    free(students);
    return 0;
}

4.2 C++ projects

Creating a Character object with new automatically invokes its constructor; deleting it runs the destructor, which is ideal for game objects and other complex resources.

#include <iostream>
#include <string>

class Character {
public:
    std::string name;
    int health;
    int attackPower;
    Character(const std::string& n, int h, int a) : name(n), health(h), attackPower(a) {
        std::cout << "Character " << name << " created" << std::endl;
    }
    ~Character() { std::cout << "Character " << name << " destroyed" << std::endl; }
    void move() { std::cout << name << " moves" << std::endl; }
    void attack() { std::cout << name << " attacks with power " << attackPower << std::endl; }
};

int main() {
    Character* player = new Character("Hero", 100, 20);
    player->move();
    player->attack();
    delete player;
    return 0;
}

4.3 Mixed C/C++ usage

When a C function returns memory allocated with malloc, C++ code must free it with free, not delete, to avoid undefined behavior.

#include <stdio.h>
#include <stdlib.h>

char* c_function() {
    char* str = (char*)malloc(100);
    if (str) strcpy(str, "Hello, World!");
    return str;
}

// C++ side
#include <iostream>
extern "C" char* c_function();

int main() {
    char* s = c_function();
    if (s) {
        std::cout << s << std::endl;
        free(s);
    }
    return 0;
}

5. Best practices and recommendations

5.1 Choosing in C++

Prefer new / delete for objects because they handle construction and destruction automatically, which is essential for resource‑heavy classes such as textures or file handles.

5.2 Smart pointers

Modern C++ (C++11+) provides std::unique_ptr, std::shared_ptr, and std::weak_ptr to manage lifetimes automatically and eliminate most manual new/delete usage.

#include <memory>
#include <fstream>

class Logger {
public:
    void log(const std::string& msg) { logFile << msg << std::endl; }
    ~Logger() { logFile.close(); }
private:
    std::ofstream logFile;
};

class ResourceManager {
public:
    std::unique_ptr<Logger> logger = std::make_unique<Logger>();
};

5.3 Additional advice

Always pair allocation and deallocation functions correctly, check for allocation failures, consider memory pools for high‑frequency small allocations, and use tools like Valgrind or AddressSanitizer to detect leaks, dangling pointers, and out‑of‑bounds accesses.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Memory ManagementCmallocsmart pointersnew/delete
Deepin Linux
Written by

Deepin Linux

Research areas: Windows & Linux platforms, C/C++ backend development, embedded systems and Linux kernel, etc.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.