개발하는 리프터 꽃게맨입니다.

[C++] malloc vs new 본문

언어/C, C++

[C++] malloc vs new

파워꽃게맨 2023. 12. 27. 12:43

malloc과 new 둘 다 동적 메모리 할당, 힙 메모리의 사용을 위해 호출하는 명령어입니다.

언뜻 보기에는 둘 다 똑같은 명령어 같고,

동적 메모리 할당할 때 malloc은 C에서 쓰고 new는 C++에서 쓰는 명령어다!

라고 이해하시는 분들도 많습니다.

 

간단하게 두 개의 공통점과 차이점, 예시를 알아보도록 하겠습니다.

 

1. 공통점

- 동적 메모리를 할당한다.

- 지정된 크기의 메모리 블록을 할당하고, 시작 주소의 포인터를 반환한다.

- 명시적으로 해제를 해줘야 한다.

 

2. malloc의 특징 

/* malloc의 기본 형식 */
#include <stdlib.h>
void *malloc(size_t size);

- malloc은 void* 를 반환한다. 

  그래서 형변환 캐스팅이 필수적입니다.

 

- size를 바이트 단위로 할당해줘야 한다.

  그리 복잡하진 않지만 번거로운 작업입니다.

 

- 생성자를 호출하지 않고, free 또한 소멸자를 호출하지 않는다.

  이것이 C++ 상에서 malloc/free가 아닌 new/delete 사용을 권장하는 이유입니다.

 

- 예시

	//4바이트 int형 공간확보
	int* num = (int*)malloc(sizeof(int));

	//sizeof(student)*8 바이트 student형 공간확보
	Student* st = (Student*)malloc(sizeof(Student) * 8);
	
	free(num);
	free(st);

 

3. new의 특징

/* new의 기본형식 */
#include <new>
(void*) operator new(size_t _Size)

-  자동으로 캐스팅을 해준다. 

  어떤 형을 사용할 건지 적어준다면, 자동으로 형변화를 해줍니다.

 

- size를 간단하게 얼마나 할당할 것인지 적어주지 않아도 된다.

  굳이 sizeof(int)*4 , 이런 식이 아닌 4 만 적어도 알아서 적절한 공간을 확보합니다.

 

- 생성자를 호출하고,  delete는 소멸자를 호출한다.

  위에서 한 번 말했던 것이고, 클래스를 다룰 때 생성자와 소멸자의 존재는 중요하기 때문에

  이 기능은 매우 중요합니다.

 

- 예시

	int* num = new int;
	Student* st = new Student[8];

	delete(num);
	delete[](st);

훨씬 간단하고 가독성이 좋습니다.

 

4. 왜 new 사용을 지향하는가?

new를 그저 가독성 때문에 사용하는 것은 아니죠. 가장 큰 특징은 '생성자와 소멸자의 호출'에 있습니다.

다음 코드를 봅시다.

#include <iostream>
using namespace std;

class Student
{
public:
	Student()
		:_name("No Name")
		,_id(0)
		,_age(0)
	{
		cout << "Created\n";
	}

	~Student()
	{
		cout << "Deleted\n";
	}

public :
	string	_name;
	int		_id;
	int		_age;
};

int main()
{
	Student* st = (Student*)malloc(sizeof(Student));
	
	cout << st->_name << endl;
	cout << st->_id << endl;
	cout << st->_age << endl;

	free(st);

}

간단한 Student 클래스와

malloc을 통해 동적 할당을 하고자 하는 코드입니다.

 

실행시키면 다음과 같이 작동합니다.

 

네,  아무것도 뜨지 않습니다.

메모리를 까보면

 

분명 클래스에는 초기화 구분이 들어가 있지만

아무런 값도 들어가 있지 않은 모습을 보여줍니다.

 

생성자, 소멸자 자체가 호출이 되지 않았기 때문입니다.

 

이제 new와 delete를 사용해볼겠습니다.

/* 클래스는 동일합니다. */
int main()
{
	Student* st = new Student;
	
	cout << st->_name << endl;
	cout << st->_id << endl;
	cout << st->_age << endl;

	delete st;
}

 

실행결과를 보면 다음과 같습니다.

 

 

네, 데이터가 들어있고 메시지가 출력된 것을 보아

생성자, 소멸자의 호출이 잘 일어난 것으로 보입니다.

 

 

5. 결론

C++에 넘어와서 객체 지향 프로그래밍을 실현시키기 위한 많은 노력을 했고, 그중 하나가 new 연산자라고 생각합니다.

OOP를 구현하는 데 있어서 생성자/소멸자의 존재는 매우 중요하고 유용하기 때문에

동적 메모리 할당에 있어 위험요소가 있는 malloc은 되도록이면 사용을 지양하고

new와 delete를 사용하는 것을 권장합니다.