icon안동민 개발노트

동적 메모리 할당


동적 메모리 할당 개요

 동적 메모리 할당은 프로그램 실행 중에 메모리를 할당하고 해제하는 기능입니다. 이를 통해 프로그램은 실행 시간에 필요한 만큼의 메모리를 사용할 수 있어, 메모리 사용의 유연성과 효율성을 높일 수 있습니다.

new 연산자

 new 연산자는 동적으로 메모리를 할당하고, 할당된 메모리의 주소를 반환합니다.

#include <iostream>
 
int main() {
    // 단일 정수 할당
    int* ptr = new int;
    *ptr = 10;
    std::cout << "값: " << *ptr << std::endl;
 
    // 초기화와 함께 할당
    int* ptr2 = new int(20);
    std::cout << "초기화된 값: " << *ptr2 << std::endl;
 
    // 메모리 해제
    delete ptr;
    delete ptr2;
 
    return 0;
}

delete 연산자

 delete 연산자는 동적으로 할당된 메모리를 해제합니다.

int* ptr = new int;
delete ptr;  // 메모리 해제
ptr = nullptr;  // 포인터를 널로 설정 (좋은 습관)

동적 배열 할당

 new[]를 사용하여 배열을 동적으로 할당할 수 있습니다.

#include <iostream>
 
int main() {
    int size;
    std::cout << "배열 크기 입력: ";
    std::cin >> size;
 
    int* arr = new int[size];
 
    for (int i = 0; i < size; i++) {
        arr[i] = i * 10;
    }
 
    for (int i = 0; i < size; i++) {
        std::cout << arr[i] << " ";
    }
    std::cout << std::endl;
 
    delete[] arr;  // 배열 메모리 해제
 
    return 0;
}

2차원 배열의 동적 할당

 2차원 배열을 동적으로 할당하는 방법은 다음과 같습니다.

#include <iostream>
 
int main() {
    int rows = 3, cols = 4;
 
    // 2차원 배열 할당
    int** matrix = new int*[rows];
    for (int i = 0; i < rows; i++) {
        matrix[i] = new int[cols];
    }
 
    // 배열 사용
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            matrix[i][j] = i * cols + j;
            std::cout << matrix[i][j] << " ";
        }
        std::cout << std::endl;
    }
 
    // 메모리 해제
    for (int i = 0; i < rows; i++) {
        delete[] matrix[i];
    }
    delete[] matrix;
 
    return 0;
}

메모리 누수 (Memory Leak)

 메모리 누수는 할당된 메모리를 해제하지 않을 때 발생합니다. 이는 프로그램의 성능 저하와 crash를 유발할 수 있습니다.

void memoryLeakExample() {
    int* ptr = new int;
    // delete ptr; // 이 줄이 없으면 메모리 누수 발생
}
 
int main() {
    for (int i = 0; i < 1000000; i++) {
        memoryLeakExample();  // 메모리 누수 누적
    }
    return 0;
}

예외 처리와 메모리 할당

 메모리 할당 실패 시 예외 처리를 통해 안전하게 프로그램을 관리할 수 있습니다.

#include <iostream>
#include <new>
 
int main() {
    try {
        int* largeArray = new int[1000000000];  // 매우 큰 배열 할당 시도
        delete[] largeArray;
    } catch (const std::bad_alloc& e) {
        std::cout << "메모리 할당 실패: " << e.what() << std::endl;
    }
 
    return 0;
}

스마트 포인터 소개

 C++ 11부터 도입된 스마트 포인터는 메모리 관리를 자동화하여 메모리 누수를 방지합니다.

#include <iostream>
#include <memory>
 
class MyClass {
public:
    MyClass() { std::cout << "생성됨" << std::endl; }
    ~MyClass() { std::cout << "소멸됨" << std::endl; }
};
 
int main() {
    {
        std::unique_ptr<MyClass> ptr = std::make_unique<MyClass>();
        // ptr은 블록이 끝날 때 자동으로 해제됩니다.
    }
    std::cout << "블록 끝" << std::endl;
 
    return 0;
}

RAII (Resource Acquisition Is Initialization)

 RAII는 자원의 수명을 객체의 수명과 연결하여 자동으로 관리하는 C++ 프로그래밍 기법입니다.

#include <iostream>
 
class RAIIExample {
private:
    int* data;
 
public:
    RAIIExample(int size) : data(new int[size]) {
        std::cout << "자원 할당" << std::endl;
    }
 
    ~RAIIExample() {
        delete[] data;
        std::cout << "자원 해제" << std::endl;
    }
};
 
int main() {
    {
        RAIIExample example(10);
        // 객체가 소멸될 때 자원이 자동으로 해제됩니다.
    }
    std::cout << "프로그램 종료" << std::endl;
 
    return 0;
}

연습 문제

  1. 동적으로 할당된 정수 배열에 사용자로부터 값을 입력받고, 이를 정렬한 후 출력하는 프로그램을 작성하세요.
  2. 학생 정보(이름, 나이, 성적)를 저장하는 클래스를 만들고, 여러 학생 객체를 동적으로 생성하여 관리하는 프로그램을 구현하세요.
  3. 2차원 동적 배열을 사용하여 행렬 곱셈을 수행하는 프로그램을 작성하세요.


참고 자료

  • C++ 공식 문서의 동적 메모리 관리 섹션 : Dynamic memory management
  • "Effective C++" by Scott Meyers (항목 16 : new와 delete를 사용할 때는 형태를 반드시 맞추자)
  • "C++ Primer" by Stanley B. Lippman, Josée Lajoie, and Barbara E. Moo (Chapter 12 : Dynamic Memory)
  • C++ Core Guidelines의 자원 관리 관련 규칙 : R : Resource management
  • "Modern C++ Programming with Test-Driven Development" by Jeff Langr (Chapter 7 : Memory Management)