C++ 포인터와 레퍼런스 완전 정복

gigyesik·2025년 6월 18일

developer-roadmap-c++

목록 보기
7/20

썸네일

C++ 포인터와 레퍼런스 완전 정복

C++에서 메모리와 객체를 보다 깊이 이해하려면 반드시 포인터와 레퍼런스를 알아야 한다. 이 글에서는 C++ 개발자 로드맵에 따라 포인터, 레퍼런스, 메모리 모델, 객체 수명, 그리고 스마트 포인터까지 폭넓게 정리해보았다.


📌 포인터(Pointer)

포인터는 다른 변수의 메모리 주소를 저장하는 변수다. 변수 자체가 아닌, 메모리 위치를 가리킨다.

int num = 10;
int* ptr = #   // ptr은 num의 주소를 저장
int value = *ptr;  // value는 10

함수 포인터

int add(int a, int b) {
    return a + b;
}

int main() {
    int (*funcptr)(int, int) = add;
    std::cout << funcptr(4, 5);  // 9
}

📌 레퍼런스(Reference)

레퍼런스는 기존 변수의 또 다른 이름(별칭)이다. 선언 시 반드시 초기화해야 하고, 이후 다른 대상을 참조할 수 없다.

int num = 10;
int& ref = num;

ref = 30;
std::cout << num;  // 30

함수에서의 사용

void swap(int& a, int& b) {
    int temp = a;
    a = b;
    b = temp;
}

📌 C++ 메모리 모델

C++의 메모리 구조는 다음 네 가지 주요 영역으로 나뉜다.

✅ Stack (스택)

  • 함수 호출 시 생성되는 지역 변수 저장
  • LIFO 방식, 자동 해제됨
void func() {
    int x = 10; // 스택에 저장
}

✅ Heap (힙)

  • 동적 메모리 영역
  • new/delete로 관리
int* p = new int(5);
// ...
delete p;

✅ Data Segment (데이터 세그먼트)

  • 전역 변수, static 변수 저장
  • 초기화 여부에 따라 분리됨
int globalVar = 10;      // 초기화된 데이터
static int staticVar;    // 비초기화(BSS)

✅ Code Segment (코드 세그먼트)

  • 실행 가능한 기계어 코드가 저장되는 영역

📌 객체의 수명(Lifetime)

C++ 객체는 다음과 같은 수명 범주를 가진다:

🟩 Static Storage Duration

  • 프로그램 전체 실행 시간 동안 유지
static int count;
int globalVar;

🟦 Thread Storage Duration

  • thread_local 키워드로 정의
  • 스레드 종료 시 소멸
thread_local int counter;

🟨 Automatic Storage Duration

  • 함수 내 지역 변수
  • 스코프 벗어나면 자동 해제
void func() {
    int localVar;
}

🟥 Dynamic Storage Duration

  • new로 할당, delete로 해제 필요
int* ptr = new int(100);
delete ptr;

📌 스마트 포인터(Smart Pointers)

🔹 unique_ptr

  • 독점 소유권
  • 복사 불가, 이동 가능
  • std::make_unique 사용 권장
std::unique_ptr<int> uptr = std::make_unique<int>(10);
std::unique_ptr<int> uptr2 = std::move(uptr); // 이동

🔸 shared_ptr

  • 참조 카운트 기반 소유
  • 마지막 참조 해제 시 메모리 해제
std::shared_ptr<int> sp1 = std::make_shared<int>(42);
std::shared_ptr<int> sp2 = sp1;
std::cout << sp1.use_count();  // 2

⚪ weak_ptr

  • shared_ptr와 함께 사용
  • 순환 참조 방지용
  • lock()으로 유효한 shared_ptr 얻기
std::weak_ptr<int> wp = sp1;
if (auto spt = wp.lock()) {
    std::cout << *spt;
}

📌 Raw Pointer와 메모리 누수

new / delete

int* num = new int(10);
delete num;

배열 메모리 할당

int* arr = new int[10];
delete[] arr;

메모리 누수 예시

void leak() {
    int* ptr = new int(100);
    // delete 누락 → 누수 발생
}

해결 방법

  • 스마트 포인터 사용
  • 소유권과 수명을 명확히 관리

✅ 마무리

C++의 강력함은 포인터와 메모리 제어에서 시작된다. 하지만 그만큼 위험성도 함께 따른다. 스마트 포인터를 잘 활용하고 객체의 수명과 메모리 구조를 이해한다면 더욱 안전하고 효율적인 C++ 코드를 작성할 수 있다.

profile
Server Dev

0개의 댓글