[C++] 동적할당 (Dynamic Allocation)
✨ 동적할당 ?
프로그램을 컴파일하는 시점에 객체의 크기를 모른다면 런타임 시점에 메모리에 객체를 만들어야 한다. 힙 메모리(heap memory)는 런타임 시점에 객체를 저장할 때 사용한다. 이때의 힙메모리는 동적메모리(dynamic memory)라고 불린다.
힙메모리의 객체는 자신의 이름을 가질 수 없기 때문에 힙 메모리에 생성한 객체는 스택 메모리에 있는 포인터로 가리켜야한다. 즉, 런타임 시점에 메모리에 객체를 만드는 작업은 스택과 힙을 모두 사용하는 것이다.
동적할당 쓰이는 경우
1) 갑자기 많은 메모리를 잡아야 할 경우 : 동적할당은 필요할 때 메모리를 잡았다가 필요 없으면 바로 해당 메모리를 해지시킬 수 있기 때문에 메모리 관리에 효율적이다. 2) 함수 리턴 후에도 메모리의 할당이 남아있게 하고 싶을 경우3) 크기를 알 수 없는 배열을 저장해야할 때
✨ 동적할당 사용 방법
new와 delete 연산자
C언어에서는 malloc(),free() functions 을 이용하여 동적할당을 하지만, C++에서는 new와 delete operators를 활용한다.
객체 할당 | new |
배열 할당 | new[] |
객체 제거 | delete |
배열 제거 | delete[] |
delete 하면 해당 포인터는 허상 포인터 (dangling pointer)가 된다.
동적 메모리는 "new"키워드를 사용하여 할당하고, "delete" 키워드를 사요하여 해제한다.
✨ 동적할당 기본 예제
힙 메모리에 크기가 유동적인 배열을 만드는 예제이다.
먼저, 앞서 설명했듯 스택 메모리에 있는 포인터, pArray를 이용하여 힙메모리의 객체를 가르킨 모습을 볼 수 있다.
#include <iostream>
using namespace std;
int main()
{
//스택에 배열에 대한 크기와 포인터 선언
int size;
int* pArray;
//사용자로부터 0보다 큰 배열의 크기 입력받기
do
{
cout << "0보다 큰 배열의 크기를 입력하세요: ";
cin >> size;
} while (size <= 0);
//힙에 배열선언
pArray = new int[size];
//배열에 값 입력받기
for (int i = 0; i < size; i++)
{
cout << i << "번째 요소의 값을 입력하세요: ";
cin >> *(pArray + i);
}
//배열의 요소 출력
cout << "배열 내부의 요소: " << endl;
for (int i = 0; i < size; i++)
{
cout << *(pArray + i) << " ";
}
//힙에서 배열제거
delete[] pArray;
return 0;
}
RESULT:
#include <iostream>
using namespace std;
int main() {
int len;
cout << "Enter length of string: ";
cin >> len;
char* str = new char[len + 1]; // new[]로 생성
cout << "Enter string: ";
cin >> str;
cout << "String value: " << str << endl;
delete[] str;
return 0;
}
위도 마찬가지로 new[]로 배열을 할당하고 delete[]로 배열을 제거하는 모습을 볼 수 있다.
✨ delete[] 한 데이터를 다시 사용하고 싶으면 ?
하지만 , delete[]연산을 하더라도 해당 메모리 내부의 데이터는 삭제되지 않는다. 즉, 해당 문자열이 사용하는 메모리는 해제되지만 메모리에 저장된 데이터는 삭제되지 않는 것이다. 이를 재활용하기 위해선 다시 동일한 메모리 주소를 가리키는 포인터를 사용하지 않도록 해야하고 재활용하기 전에 메모리를 초기화 하는 것이 좋다.
char* str = new char[len+1]; //동적으로 메모리 할당
// ...
delete[] str; // 메모리 해제
//메모리 하기 전에 초기화
str=nullptr; // 포인터를 null로 초기화
// 또는
for (int i=0;i<len+1;i++)
str[i]='\0'; // 메모리 내용을 null 문자로 초기화
✨ heap 메모리 사용 주의점
1. 메모리 할당 없이 제거
new 키워드를 사용하지 않았는데 delete 키워드를 사용하는 경우이다.
2. 제거 없이 메모리 할당하기 (메모리 누수, memory leak)
메모리 누수는 new 키워드로 힙 메모리 위에 영역을 잡은 뒤, delete 키워드로 제거하지 않았을 때 발생한다. 메모리 누수가 발생하면 누수가 발생한 메모리 위치를 사용할 수 없으며 메모리가 부족한 경우 시스템에 큰 문제를 야기한다.
3. 허상 포인터 (dangling pointer) 허상 포인터는 포인터가 가르키고 있는 객체를 delete 키워드로 제거했는데 포인터를 활용하려고 할 때 발생한다.