1. 포인터 사용으로 발생할 수 있는 이슈들
포인터는 C++의 강력한 도구이지만, 그와 동시에 치명적인 이슈를 일으키는 원인이기도 하다
포인터 사용으로 발생할 수 있는 이슈들은 대표적으로 다음과 같은 것들이 있다
1) 메모리 누수(Memory Leak)
메모리를 할당하고 해제하지 않을 경우 힙에 해당 객체가 계속 남게 되는데, 이 경우 해당 코드가 실행될 때마다 힙 메모리를 잡아먹고, 사용하지도 않는 메모리가 계속 할당되어 있는 메모리 누수 문제가 발생한다 보통 c++에서 [new - delete] 쌍을 맞추면 된다고는 하지만, 코드가 복잡해질수록 포인터끼리 얽히기 쉬워 주해야 한다
2) 널 포인터(nullptr)
아무것도 가리키지 않고 있는 널 포인터를 통해 무언가에 접근할 경우 발생하는 문제이다. 포인터 사용 시 널 포인터 체크를 생활화함으로써 어느 정도 예방할 수 있다
3) 댕글링 포인터(Dangling Pointer)
포인터가 이미 할당이 해제된 메모리를 가리키고 있고, 이를 통해 접근할 경우 발생하는 문제이다. 발생하기도 쉽고 치명적인 이슈이므로 주의해야 한다
2. 스마트 포인터
앞서 이야기한 포인터 사용으로 발생할 수 있는 여러가지 문제점을 보완하기 위해 C+11 이상부터 스마트 포인터를 지원하는데, 스마트 포인터는 포인터처럼 사용하는 클래스 템플릿으로 마모리를 자동으로 해제해 준다
C++에 존재하는 스마트 포인터 [ unique_ptr, shared_ptr, weak_ptr ]에 대해 자세히 알아보자
3. unique_ptr
unique_ptr은 객체에 대한 단일 소유권을 관리한다 객체의 소유권을 명확히 하고 소유권 이전을 통해 효율적인 자원관리가 가능하다
아래 그림처럼 새로운 소유권을 주장할 때 move를 통해 소유권을 이동하는 식으로 관리된다

간단한 unique_ptr 사용 예제코드를 확인해 보자
//unique_ptr 사용법
#include <iostream>
#include <memory> // unique_ptr이 들어있는 헤더파일
using namespace std;
int main() {
// unique_ptr 생성방법
unique_ptr<int> ptr1 = make_unique<int>(10);
// unique_ptr이 관리하는 값 출력
cout << "ptr1의 값: " << *ptr1 << endl;
//Output: "ptr1의 값: 10"
// unique_ptr은 복사가 불가능
// unique_ptr<int> ptr2 = ptr1; // 컴파일 에러 발생!
// 소유권 이동 (move 사용)
unique_ptr<int> ptr2 = move(ptr1);
if (!ptr1) {
cout << "ptr1은 이제 비어 있습니다." << endl;
}
cout << "ptr2의 값: " << *ptr2 << endl;
// 범위를 벗어나면 메모리 자동 해제
return 0;
}
4. shared_ptr
shared_ptr은 레퍼런스 카운트를 관리한다
레퍼런스 카운트란 현재 객체를 참조하는 포인터의 개수를 카운팅 하는 것이다. 레퍼런스 카운트가 0이 되면 객체는 자동으로 메모리 해제가 된다
이를 활용해서 Dangling Pointer 및 Memory Leak 문제를 효과적으로 방지할 수 있다
아래 그림을 보면 레퍼런스 카운터의 동작을 나타낸 것이다

간단한 shared_ptr 사용 예제코드를 확인해 보자
#include <iostream>
#include <memory> // shared_ptr 사용
using namespace std;
int main() {
// shared_ptr 생성
shared_ptr<int> ptr1 = make_shared<int>(10);
// ptr1의 참조 카운트 출력
cout << "ptr1의 참조 카운트: " << ptr1.use_count() << endl; // 출력: 1
// ptr2가 ptr1과 리소스를 공유
shared_ptr<int> ptr2 = ptr1;
cout << "ptr2 생성 후 참조 카운트: " << ptr1.use_count() << endl; // 출력: 2
// ptr2가 범위를 벗어나면 참조 카운트 감소
ptr2.reset();
cout << "ptr2 해제 후 참조 카운트: " << ptr1.use_count() << endl; // 출력: 1
// 범위를 벗어나면 ptr1도 자동 해제
return 0;
}
5. weak_ptr
weak_ptr은 객체의 소유권을 공유하지 않는다
다른 스마트 포인터와 다르게 레퍼런스 카운트를 증가시키지 않는 약한 참조를 한다
shared_ptr은 유용하지만 순환참조가 발생할 수 있다
순환 참조란, 두 개 이상의 객체가 서로를 shared_ptr로 가리켜 참조하는 상황을 말한다.
이러한 순환 참조는 메모리 누수를 유발할 수 있다
이 상황에서 서로 순환하고 있는 shared_ptr 중 하나를 weak_ptr로 대체하면 순환 고리가 끊어지게 되므로 문제를 해결할 수 있다
정리하면 shared_ptr은 관찰과 소유를 하는 반면, weak_ptr은 관찰만 한다고 표현한다

'C++' 카테고리의 다른 글
| [C++] System() 함수 - "cls" , "pause" (0) | 2025.06.13 |
|---|---|
| [C++] 얕은 복사 vs 깊은 복사 (1) | 2025.06.12 |
| [C++] 헤더파일 중복방지 #Pragma once vs #ifndef ~ endif (0) | 2025.06.10 |
| [C++] 깔끔한 코드 작성법 - 헤더파일과 소스파일을 나누는 이유 (0) | 2025.06.05 |
| [C++] String 클래스 정리 및 함수 사용 (0) | 2025.06.04 |