본문 바로가기

malloc/free 와 new/delete

@iamrain2025. 8. 26. 19:48

C++에서 동적 메모리 할당은 C 언어로부터 물려받은 `malloc`/`free` 함수와 C++ 고유의 `new`/`delete` 연산자를 통해 이루어질 수 있다.

두 방식은 단순히 메모리를 할당하고 해제하는 기능을 넘어 객체의 생명주기와 타입 시스템에 깊이 관여한다는 점에서 중요한 차이를 보인다.

malloc / free

함수 function

`malloc`과 `free`는 C 언어의 표준 라이브러리에 포함된 함수로 `` 헤더 파일에 선언되어 있다. (C에서는 `<stdlib.h>`)

생성자 / 소멸자 미호출

`malloc`은 지정된 크기의 메모리 블록을 할당할 뿐, 해당 메모리에 객체를 생성하지 않는다. 따라서 클래스의 생성자가 호출되지 않는다.

`free` 역시 할당된 메모리를 해제할 뿐, 소멸자를 호출하지 않는다.

타입 안정성 Type Safety

`malloc`은 `void` 타입의 포인터를 반환한다.

이 포인터를 사용하기 위해서는 반드시 원하는 타입으로 명시적 형변환(casting)이 필요하다. 이 과정에서 오류가 발생할 가능성이 있다.

크기 지정

할당할 메모리의 크기를 `sizeof` 연산자 등을 이용해 바이트 단위로 직접 계산하여 전달해야 한다.

재할당

`realloc` 함수를 통해 이미 할당된 메모리 블록의 크기를 변경할 수 있다.

new / delete

연산자 Operator

`new`와 `delete`는 C++ 언어 자체에 내장된 연산자다.

생성자 / 소멸자 호출

`new` 연산자는 메모리 할당과 동시에 객체의 생성자를 호출하여 객체를 초기화한다.

`delete` 연산자는 객체의 소멸자를 호출하여 리소스를 정리한 후 메모리를 해제한다. 이는 객체지향 프로그래밍에서 매우 중요한 특징이다.

타입 안정성 Type Safety

`new` 연산자는 할당하려는 객체의 타입을 정확히 알고 있으며, 해당 타입의 포인터를 반환한다. 따라서 별도의 형변환이 필요없다.

크기 자동 계산

컴파일러가 할당할 객체의 타입을 알고 있으므로, 개발자가 직접 크기를 계산할 필요 없이 자동으로 크기를 계산한다.

오버로딩 Overloading

클래스별로 `new`와 `delete` 연산자를 재정의(overloading)하여 메모리 할당 및 해제 방식을 커스터마이징할 수 있다.

예외 처리

메모리 할당에 실패했을 경우, `malloc`이 `NULL`을 반환하는 반면 `new`는 기본적으로 `std::bad_alloc` 예외(exception)를 발생시킨다.

구분 malloc / free new / delete
분류 라이브러리 함수 언어 연산자
생성자/소멸자 호출 안 함 호출 함
반환 타입 void* (형변환 필요) 해당 객체 타입 포인터 (형변환 불필요)
메모리 크기 직접 계산하여 전달 컴파일러가 자동 계산
실패 시 동작 NULL 반환 std::bad_alloc 예외 발생
재정의 불가능 가능

 

실습 코드

#include <iostream>
#include <cstdlib>

class MyClass {
private:
    int _value;
public:
    MyClass(int val) : _value(val) {
        std::cout << "Constructor called. Value = " << _value << std::endl;
    }

    ~MyClass() {
        std::cout << "Destructor called. Value = " << _value << std::endl;
    }

    void printValue() {
        std::cout << "Value is: " << _value << std::endl;
    }
};

int main() {
    std::cout << "--- 1. Using new/delete ---" << std::endl;
    MyClass* p1 = new MyClass(10);
    p1->printValue();
    delete p1;

    std::cout << "--- 2. Using malloc/free ---" << std::endl;
    MyClass* p2 = (MyClass*)malloc(sizeof(MyClass));
    if (p2 == NULL) {
        std::cerr << "malloc failed" << std::endl;
        return 1;
    }
    std::cout << "Memory allocated with malloc, but constructor was not called." << std::endl;

    free(p2);
    std::cout << "Memory freed with free, but destructor was not called." << std::endl;

    return 0;
}

실행 결과

 

정리

  • `malloc` / `free`
    `malloc`과 `free`를 사용한 경우에는 생성자와 소멸자가 전혀 호출되지 않았다. 만약 `MyClass`가 동적으로 다른 메모리를 할당하는 등의 복잡한 작업을 수행했다면, `free`만으로는 해당 메모리가 해제되지 않아 메모리 누수가 발생하게 된다
  • `new` / `delete`
    `new`를 사용했을 때 생성자가 호출되어 `_value`가 10으로 초기화되었고, `delete`를 사용했을 때 소멸자가 호출되어 객체가 안전하게 제거되었다.

C++에서 `malloc` / `free` 보다 `new` / `delete`를 사용하는 것이 객체의 생명주기를 올바르게 관리하고 타입 안정성을 보장하므로 권장된다.

iamrain
@iamrain :: Annals of Unreal

iamrain 님의 블로그 입니다.

공감하셨다면 ❤️ 구독도 환영합니다! 🤗

목차