동적 메모리 (new/delete)
Coddy C++ 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨 — 104개 중 14번째.
이제 포인터와 참조를 이해했으므로, 동적 메모리 할당을 통해 이를 실제로 활용해 보겠습니다. new와 delete 연산자를 사용하면 런타임에 힙(heap) 영역에서 객체를 생성하고 소멸시킬 수 있습니다.
new를 사용하여 메모리를 할당하고 그에 대한 포인터를 반환받으세요:
int* num = new int; // 단일 정수 할당
*num = 42; // 포인터를 통해 값 할당
Player* player = new Player("Hero"); // 객체 할당모든 new는 메모리를 해제하기 위해 그에 대응하는 delete가 있어야 합니다:
delete num; // 단일 객체 해제
delete player; // 소멸자를 호출한 후, 메모리를 해제함배열의 경우, new[]와 delete[]를 사용합니다:
int* scores = new int[5]; // 5개의 정수 배열 할당
scores[0] = 100;
delete[] scores; // 배열 해제 - 대괄호에 주의하세요!피해야 할 일반적인 실수:
// 메모리 누수 - delete를 잊음
int* ptr = new int(10);
ptr = new int(20); // 첫 번째 할당에 대한 접근 권한을 잃음!
// 댕글링 포인터 - delete 후 사용
delete ptr;
*ptr = 5; // 정의되지 않은 동작!
// 일치하지 않는 delete
int* arr = new int[10];
delete arr; // 잘못됨! delete[]를 사용해야 함삭제한 후에는 실수로 재사용하는 것을 방지하기 위해 포인터를 nullptr로 설정하세요. 수동 메모리 관리는 오류가 발생하기 쉬우므로 현대 C++에서는 스마트 포인터를 선호하며, 이에 대해서는 다음에 살펴보겠습니다.
챌린지
쉬움new와 delete를 사용한 동적 메모리 할당을 보여주는 간단한 메시지 저장 시스템을 만들어 보겠습니다.
코드를 구성하기 위해 두 개의 파일을 생성합니다:
MessageBox.h: 메시지 배열을 동적으로 관리하는MessageBox클래스를 정의합니다. 클래스는 다음을 포함해야 합니다:- 동적으로 할당된 문자열 배열을 가리키는 private 포인터
- 현재 메시지 개수를 추적하는 private 정수
- 최대 용량을 저장하는 private 정수
- 용량을 인자로 받아
new[]를 사용하여 배열을 할당하는 생성자 delete[]를 사용하여 메모리를 적절히 해제하고"MessageBox destroyed"를 출력하는 소멸자- 공간이 있으면 메시지를 추가하고 성공 시
true, 가득 찼을 시false를 반환하는addMessage(string msg)메서드 - 저장된 각 메시지를 개별 줄에 출력하는
printAll()메서드
main.cpp: 입력으로부터 용량 값과 메시지 개수를 읽습니다. 그런 다음 그 개수만큼의 메시지 문자열을 읽습니다.new를 사용하여 힙에MessageBox를 생성하고, 모든 메시지를 추가한 뒤,printAll()을 호출하고, 메모리 해제를 위해 MessageBox를 적절히 delete 합니다.
입력 형식은 다음과 같습니다:
- 첫 번째 줄: 용량 (정수)
- 두 번째 줄: 추가할 메시지의 개수 (정수)
- 다음 줄들: 한 줄당 하나의 메시지
주의: 모든 new에는 그에 대응하는 delete가 필요하며, 모든 new[]에는 그에 대응하는 delete[]가 필요합니다. 삭제 후에는 포인터를 nullptr로 설정하는 것이 좋은 습관입니다.
main.cpp에서 #include "MessageBox.h"를 사용하여 헤더 파일을 포함하세요.
치트 시트
new를 사용하여 힙(heap)에 메모리를 동적으로 할당하고 해당 메모리에 대한 포인터를 얻습니다:
int* num = new int; // 단일 정수 할당
*num = 42; // 포인터를 통해 값 할당
Player* player = new Player("Hero"); // 객체 할당메모리를 해제하려면 모든 new에 대응하는 delete가 있어야 합니다:
delete num; // 단일 객체 해제
delete player; // 소멸자를 호출한 후 메모리 해제배열의 경우, new[]와 delete[]를 사용합니다:
int* scores = new int[5]; // 5개의 정수 배열 할당
scores[0] = 100;
delete[] scores; // 배열 해제 - 대괄호에 주의하세요!피해야 할 일반적인 실수들:
// 메모리 누수(Memory leak) - delete를 잊음
int* ptr = new int(10);
ptr = new int(20); // 첫 번째 할당된 메모리에 대한 접근 권한을 잃음!
// 댕글링 포인터(Dangling pointer) - delete 후 사용
delete ptr;
*ptr = 5; // 정의되지 않은 동작(Undefined behavior)!
// 잘못된 delete 사용
int* arr = new int[10];
delete arr; // 잘못됨! delete[]를 사용해야 함삭제한 후에는 실수로 재사용하는 것을 방지하기 위해 포인터를 nullptr로 설정하십시오.
직접 해보기
#include <iostream>
#include <string>
#include "MessageBox.h"
using namespace std;
int main() {
int capacity;
int numMessages;
// 용량과 메시지 수를 읽습니다
cin >> capacity;
cin >> numMessages;
cin.ignore(); // 숫자 뒤의 개행 문자를 제거합니다
// TODO: new를 사용하여 힙에 MessageBox를 생성합니다
// TODO: 모든 메시지를 읽고 MessageBox에 추가합니다
for (int i = 0; i < numMessages; i++) {
string message;
getline(cin, message);
// MessageBox에 메시지를 추가합니다
}
// TODO: 모든 메시지를 표시하기 위해 printAll()을 호출합니다
// TODO: 메모리 해제를 위해 MessageBox를 삭제합니다
// 삭제 후 포인터를 nullptr로 설정하는 것을 잊지 마세요
return 0;
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.