Computer >> 컴퓨터 >  >> 프로그래밍 >> C++

C++에서 블록 내부에 생성된 객체는 어디에 저장될까?

C++ 프로그램이 컴파일될 때 변수와 객체가 메모리의 어느 위치에 저장되는지 아는 것은 메모리 관리를 이해하는 데 매우 중요합니다. C++에서 객체는 크게 두 가지 메모리 영역에 저장됩니다.

1. 스택(Stack)

블록({}) 내부에서 선언된 모든 지역 변수와 객체는 스택 영역에 저장됩니다. main 함수 역시 하나의 함수이므로, 그 안에서 선언된 요소들도 모두 스택에 저장됩니다.

2. 힙(Heap)

힙 영역은 객체가 동적으로 할당될 때 사용되는 공간입니다. 런타임 중에 new 연산자를 통해 생성된 객체는 모두 힙에 저장됩니다.

블록 내 객체의 생명 주기

블록이나 함수 내부에서 선언된 객체의 유효 범위(scope)는 해당 객체가 생성된 블록으로 제한됩니다. 즉, 블록 안에서 객체를 생성하면 스택에 저장되고, 프로그램의 제어 흐름이 블록이나 함수를 벗어나는 순간 객체는 자동으로 소멸(제거)됩니다. 이때 소멸자(destructor)가 자동으로 호출됩니다.

반면, 동적으로 할당된 객체(new 연산자로 런타임에 생성)는 힙에 저장됩니다. 이러한 객체는 블록이 끝나도 자동으로 소멸되지 않으므로, 반드시 delete 키워드를 사용하여 명시적으로 제거해야 합니다. 제거하지 않으면 메모리 누수(memory leak)가 발생할 수 있습니다.

예제 코드

다음 예제를 통해 스택과 힙에 저장되는 객체의 차이를 더 잘 이해할 수 있습니다.

#include <iostream>
using namespace std;
class Box {
    int width;
    int length;
public:
    Box(int length = 0, int width = 0) {
        this->length = length;
        this->width = width;
    }
    ~Box() {
        cout << "Box is destroying" << endl;
    }
    int get_len() {
        return length;
    }
    int get_width() {
        return width;
    }
};
int main() {
    {
        Box b(2, 3); // b는 스택에 저장됨
        cout << "Box dimension is:" << endl;
        cout << "Length : " << b.get_len() << endl;
        cout << "Width :" << b.get_width() << endl;
    }
    cout << "\tExitting block, destructor" << endl;
    cout << "\tAutomatically call for the object stored in stack." << endl;
    Box* box_ptr; {
        // 객체는 힙 영역에 저장되고,
        // 지역 포인터 변수만 스택에 저장됨
        Box* box_ptr1 = new Box(5, 6);
        box_ptr = box_ptr1;
        cout << "---------------------------------------------------" << endl;
        cout << "Box 2 dimension is:" << endl;
        cout << "length : " << box_ptr1->get_len() << endl;
        cout << "width :" << box_ptr1->get_width() << endl;
        delete box_ptr1;
    }
    cout << "length of box2 : " << box_ptr->get_len() << endl;
    cout << "width of box2 :" << box_ptr->get_width() << endl;
}

실행 결과

Box dimension is:
Length : 2
Width :3
Box is destroying
        Exitting block, destructor
        Automatically call for the object stored in stack.
---------------------------------------------------
Box 2 dimension is:
length : 5
width :6
Box is destroying
length of box2 : 0
width of box2 :0

결과 분석

첫 번째 Box 객체 b는 블록 내부에 선언되었기 때문에 스택에 저장됩니다. 블록을 벗어나는 순간 소멸자가 자동으로 호출되어 "Box is destroying" 메시지가 출력됩니다.

두 번째 Box 객체는 new 연산자로 힙에 할당되었습니다. 여기서 주목할 점은 실제 객체 데이터는 힙에 저장되지만, 객체를 가리키는 포인터 변수(box_ptr1) 자체는 스택에 저장된다는 것입니다. delete를 호출하면 소멸자가 실행되어 두 번째 "Box is destroying" 메시지가 출력됩니다.

마지막 출력에서 box_ptr의 값이 0으로 나타나는 이유는, delete로 이미 해제된 메모리에 접근했기 때문입니다. 이처럼 delete 이후에는 해당 포인터를 더 이상 사용해서는 안 되며, 안전한 코드를 위해 포인터를 nullptr로 설정하는 것이 좋은 습관입니다.