new allocates heap memory AND runs the object's constructor in one step; delete runs its destructor AND releases the memory. This is the key difference from C's malloc/free, which are purely memory operations with no awareness of C++ constructors, destructors, or types at all. new[] and delete[] handle arrays specifically and must always be paired with each other — mixing new with delete[], or new[] with plain delete, is undefined behavior. In practice, modern C++ style strongly discourages calling new/delete directly in ordinary code at all, preferring smart pointers (covered in their own topic) and standard containers that manage this automatically.
new and delete: allocation plus construction
Unlike C's malloc, new here actually RUNS Person's constructor on the allocated memory; delete correspondingly runs its destructor before releasing the memory — malloc/free would have no idea Person even had a constructor to call.
class Person {
public:
Person(std::string name) : name_(name) {
std::cout << "Constructing " << name_ << "\n";
}
~Person() {
std::cout << "Destructing " << name_ << "\n";
}
private:
std::string name_;
};
Person* p = new Person("Alice"); // allocates AND constructs
delete p; // destructs AND deallocatesnew[] and delete[]: arrays need the matching pair
Mixing these is undefined behavior, not a caught error — the array form tracks the element count somewhere the compiler knows to look, and using the wrong delete form corrupts that bookkeeping.
int* arr = new int[10];
delete[] arr; // correct — matches new[]
// int* bad = new int[10];
// delete bad; // UNDEFINED BEHAVIOR — mismatched with new[]Why modern C++ avoids writing new/delete directly
Every manual new needs a perfectly-matched delete on every possible code path, including exception paths — genuinely easy to get wrong in anything beyond trivial code. Smart pointers (std::unique_ptr, std::shared_ptr) and standard containers (std::vector, std::string) wrap this exact allocation/deallocation pairing automatically via RAII, which is why idiomatic modern C++ code rarely calls new or delete explicitly at all, reserving them mainly for implementing lower-level building blocks like smart pointers themselves.