[C++] 객체 지향 프로그래밍 - 동적 할당

Taeil Nam·2022년 11월 1일
0

C++

목록 보기
7/13
post-thumbnail

동적 할당

  • 필요한 만큼의 메모리를 할당 받아 사용하는 것.
  • 런타임에 운영체제에게 특정 크기 만큼의 메모리 할당을 요청하여 할당 받음.
  • 메모리 할당 후 사용이 끝나면 꼭 메모리를 반납을 해줘야 함.
  • 메모리 반납을 해주지 않을 경우, 메모리 누수(Memory Leak)가 발생하여 메모리를 계속 사용하게됨.
  • 동적 할당 받은 메모리는 Heap 메모리 영역 사용.

malloc(), free()

  • C언어부터 사용된 동적 할당을 위한 함수.
  • malloc() 함수는 운영 체제로부터 할당 받은 메모리 주소를 void 자료형으로 반환해줌.
  • void 자료형 반환 = 메모리에 뭐가 저장될지 모르겠으니, 너가 알아서 형변환해서 사용해라.
  • 할당 받을 메모리 크기를 직접 지정.

예제 코드

#include <iostream>

using namespace std;

class Monster
{
public:
	Monster() { cout << "Monster()" << endl; };		// 기본 생성자.
	~Monster() { cout << "~Monster()" << endl; };	// 소멸자.
public:
	int _hp = 100;
};

int main()
{
	Monster* m = (Monster*)malloc(sizeof(Monster));
    // malloc()으로 Monster 객체 크기 만큼의 메모리 주소를 void 형으로 동적 할당 받고, Monster로 형변환.
    
	free(m); // 동적 할당 받은 메모리 반납.

	return 0;
}

결과


new, delete

  • C++언어에서 동적 할당을 위해 추가된 연산자.
  • void 자료형이 아닌, 객체의 자료형을 반환.
  • 할당 받을 메모리 크기를 알아서 할당해줌.

예제 코드

#include <iostream>

using namespace std;

class Monster
{
public:
	Monster() { cout << "Monster()" << endl; };
	~Monster() { cout << "~Monster()" << endl; };
public:
	int _hp = 100;
};

int main()
{
	Monster* m = new Monster; // new 연산자를 사용하여 Monster 자료형의 메모리 크기만큼 동적 할당. (생성자 호출)
	delete m; // 동적 할당 받은 메모리 반납. (소멸자 호출)

	cout << endl;

	Monster* m2 = new Monster[5];
    // new 연산자를 사용하여 Monster 자료형의 메모리 크기만큼 5개 동적 할당. (생성자 5개 호출)
    
	delete[5] m2; // 동적 할당 받은 메모리 주소 5개 반납.
	return 0;
}

결과


malloc(), free() 와 new, delete 차이점

  1. malloc(), free()는 클래스의 생성자와 소멸자를 호출하지 않지만 new, delete는 호출한다.
  2. malloc(), free()는 할당 받을 메모리 크기를 직접 입력하지만 new, delete는 자동으로 할당.
  3. malloc(), free()는 메모리 주소를 void 자료형으로 반환하지만 new, delete는 객체의 자료형으로 반환.
  4. new, delete는 [] 기호를 사용하여, 배열처럼 여러 개의 메모리를 동적 할당 받을 수 있음.

메모리 반납시, 반납해야할 메모리 크기를 어떻게 아는걸까?

  • c++언어에서는 기본적으로 CRT(C언어 런타임 라이브러리)의 Heap 관리자를 통해 Heap 영역을 사용.
  • 동적 할당을 받을 때, Heap 관리자는 요청한 만큼의 메모리 크기만 받는 것이 아니라, 동적 할당의 정보를 저장하기 위한 공간인 헤더 영역까지 할당을 받음.
  • 헤더 영역은 실제 동적 할당 메모리의 바로 앞에 붙어있으며, 할당 받은 메모리 크기 등의 정보들이 저장되어 있음.
  • 메모리 반납시 헤더의 내용을 참고하여 해당 메모리 크기 만큼 메모리 반납 수행.

주의 사항

메모리 누수 (Memory Leak)

  • 동적 할당 받은 메모리 사용 후, 반납을 하지 않았을 경우 발생.
  • 더 이상 사용하지 않는 메모리이지만, 반납을 해주지 않아 해당 메모리 크기만큼 메모리가 계속 사용되며 낭비됨.
  • 언젠가 Heap 메모리가 부족해지는 Heap Overflow 가 발생하여 프로그램이 멈출 수 있음.

예제코드

#include <iostream>

using namespace std;

class Monster
{
public:
	Monster() { cout << "Monster()" << endl; };
	~Monster() { cout << "~Monster()" << endl; };
public:
	int _hp = 100;
};

int main()
{
	while (true)
	{
		Monster* m1 = new Monster; // 반복문 수행마다 4바이트씩 동적 할당.
        // 메모리 반납을 해주지 않아 반복문 수행마다 4바이트씩 메모리 누수 발생.
	}

	return 0;
}

결과

  • 메모리 동적 할당 후 반납을 해주지 않아, 반복문이 수행될 때마다 메모리가 계속 증가.

Use-After-Free

  • 반납을 완료한 동적 할당 메모리를 참조하여 사용할 경우 발생.
  • 이미 반납된 메모리이므로, 다른 곳에서 할당 받아 사용할 가능성도 있으며, 이때 해당 메모리를 참조하여 값을 변경할 경우 메모리 오염(Memory corruption) 발생.

예제 코드

#include <iostream>

using namespace std;

class Monster
{
public:
	Monster() { cout << "Monster()" << endl; };
	~Monster() { cout << "~Monster()" << endl; };
public:
	int _hp = 100;
};

int main()
{
	Monster* m1 = new Monster;
	delete m1;

	cout << "메모리 오염 전 hp : " << m1->_hp << endl;
	m1->_hp = 200;
	cout << "메모리 오염 후 hp : " << m1->_hp << endl;

	return 0;
}

결과

  • 메모리 반납 후 해당 메모리의 값이 초기화(0xdddddddd)됨.
  • 이미 반납한 메모리를 다시 참조하여 값(200)을 넣어서 메모리 오염 발생.

0개의 댓글