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

 RAII (Resource Acquisition Is Initialization)는 자원의 수명을 객체의 수명과 연결하여 자동으로 관리하는 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)