동적 메모리 할당

2025. 3. 28. 08:43Programming Languages/C++

6.3 동적 메모리 할당

6.3.1 정적 vs 동적 메모리

C++에서 메모리는 크게 두 가지 방식으로 할당됩니다:

  1. 정적 메모리 할당:
    • 컴파일 시간에 크기가 결정됩니다.
    • 스택 메모리 또는 전역/정적 메모리에 저장됩니다.
    • 변수 수명이 정해져 있습니다(블록이 끝나거나 프로그램이 종료될 때).
    int num = 42;           // 스택 메모리에 할당
    static int counter = 0; // 정적 메모리에 할당
    
  2. 동적 메모리 할당:
    • 실행 시간에 크기가 결정됩니다.
    • 힙 메모리에 저장됩니다.
    • 명시적으로 해제할 때까지 메모리가 유지됩니다.
    int* dynamicNum = new int;  // 힙 메모리에 할당
    *dynamicNum = 42;
    delete dynamicNum;          // 할당된 메모리 해제
    

6.3.2 new와 delete 연산자

C++에서는 new와 delete 연산자를 사용하여 힙 메모리를 동적으로 할당하고 해제합니다:

#include <iostream>

int main() {
    // 단일 변수 동적 할당
    int* ptr = new int;  // 메모리 할당
    *ptr = 42;           // 값 설정
    
    std::cout << "동적 할당된 정수: " << *ptr << std::endl;
    
    delete ptr;          // 메모리 해제
    
    // 초기화와 함께 할당
    double* dPtr = new double(3.14159);
    std::cout << "동적 할당된 실수: " << *dPtr << std::endl;
    
    delete dPtr;
    
    // 배열 동적 할당
    int size = 5;
    int* arr = new int[size];  // 크기 5인 정수 배열 할당
    
    // 배열 초기화
    for (int i = 0; i < size; i++) {
        arr[i] = i * 10;
    }
    
    // 배열 출력
    for (int i = 0; i < size; i++) {
        std::cout << "arr[" << i << "] = " << arr[i] << std::endl;
    }
    
    delete[] arr;  // 배열 메모리 해제 ([] 표기 중요!)
    
    return 0;
}

주의사항:

  • new로 할당한 메모리는 반드시 delete로 해제해야 합니다.
  • new[]로 할당한 배열은 반드시 delete[]로 해제해야 합니다.
  • 이미 해제된 메모리를 다시 해제하면 정의되지 않은 동작이 발생합니다.
  • 메모리 누수(memory leak)를 방지하기 위해 모든 동적 할당 메모리를 적절히 해제해야 합니다.

6.3.3 동적 메모리 할당 오류 처리

C++에서 메모리 할당 실패 시 예외 처리 방법:

#include <iostream>
#include <new>     // std::bad_alloc 예외 클래스
#include <cstdlib> // std::exit 함수

int main() {
    try {
        // 매우 큰 메모리 블록 할당 시도
        int* hugeArray = new int[1000000000000];  // 가능성 있는 메모리 할당 실패
        
        // 이 코드는 메모리 할당이 성공하면 실행됨
        std::cout << "메모리 할당 성공" << std::endl;
        delete[] hugeArray;
    }
    catch (const std::bad_alloc& e) {
        // 메모리 할당 실패 시 예외 처리
        std::cerr << "메모리 할당 실패: " << e.what() << std::endl;
    }
    
    // 예외를 던지지 않는 버전 (C++11)
    int* ptr = new(std::nothrow) int[1000000000];
    if (ptr == nullptr) {
        std::cerr << "메모리 할당 실패 (nothrow)" << std::endl;
    } else {
        std::cout << "메모리 할당 성공 (nothrow)" << std::endl;
        delete[] ptr;
    }
    
    return 0;
}

6.3.4 메모리 누수와 스마트 포인터 소개

메모리 누수는 할당된 메모리를 해제하지 않을 때 발생하는 문제입니다:

void memoryLeakExample() {
    int* ptr = new int(42);
    // delete ptr; 가 없으면 메모리 누수 발생
}  // 함수가 종료되면 ptr은 소멸되지만, 할당된 메모리는 그대로 남음

C++11부터는 스마트 포인터를 사용하여 메모리 관리를 자동화할 수 있습니다:

#include <iostream>
#include <memory>  // 스마트 포인터

int main() {
    // 고유 소유권 스마트 포인터
    std::unique_ptr<int> uptr = std::make_unique<int>(42);  // C++14
    // std::unique_ptr<int> uptr(new int(42));  // C++11
    
    std::cout << "unique_ptr 값: " << *uptr << std::endl;
    
    // 함수 종료 시 자동으로 메모리 해제
    
    // 공유 소유권 스마트 포인터
    std::shared_ptr<int> sptr1 = std::make_shared<int>(100);
    std::cout << "shared_ptr 값: " << *sptr1 << std::endl;
    
    {
        std::shared_ptr<int> sptr2 = sptr1;  // 참조 카운트 증가
        std::cout << "참조 카운트: " << sptr1.use_count() << std::endl;  // 2
        
        // sptr2 값 변경 시 sptr1도 영향 받음(같은 객체 가리킴)
        *sptr2 = 200;
        std::cout << "sptr1 값: " << *sptr1 << std::endl;  // 200
    }  // 블록 종료 시 sptr2 소멸, 참조 카운트 감소
    
    std::cout << "블록 이후 참조 카운트: " << sptr1.use_count() << std::endl;  // 1
    
    // weak_ptr: 소유권 없이 shared_ptr 관찰
    std::weak_ptr<int> wptr = sptr1;
    
    if (auto temp = wptr.lock()) {  // shared_ptr 획득 시도
        std::cout << "weak_ptr를 통한 값 접근: " << *temp << std::endl;
    } else {
        std::cout << "weak_ptr가 가리키는 객체 소멸됨" << std::endl;
    }
    
    return 0;
}  // sptr1 소멸, 메모리 자동 해제

스마트 포인터의 장점:

  • RAII(Resource Acquisition Is Initialization) 패턴을 통한 자동 메모리 관리
  • 예외 안전성 보장
  • 소유권 모델을 명시적으로 표현
  • 교차 참조 문제 해결(shared_ptr과 weak_ptr 조합)

 

'Programming Languages > C++' 카테고리의 다른 글

고급 포인터 주제  (0) 2025.03.28
참조  (0) 2025.03.28
포인터의 기본  (0) 2025.03.28
포인터와 참조  (0) 2025.03.28
챕터5. 실습 문제  (0) 2025.03.28