C++ STL 에서 제공하는 클래스 템플릿으로, 포인터를 객체처럼 관리하면서 메모리 관리를 자동화 함.
개발자가 직접 동적 메모리를 delete 하지 않아도 memory leak을 방지할 수 있음.
smart pointer는 RAII (Resource Acquisition Is Initalization) 원칙을 따른다. 즉, 스마트 포인터 객체의 생명 주기가 끝날 때 (스코프를 벗어날 때), 내부에서 관리하던 동적 메모리를 자동으로 해제함.
std::unique_ptr
std::move 사용)std::shared_ptr
shared_ptr 이 파괴될 때 메모리를 해제.std::weak_ptr
std::shared_ptr 과 함께 사용되며, 자원의 Reference Counting에 영향을 주지 않음.std::shared_ptr의 순환 참조 문제를 해결하기 위해 사용#include <iostream>
#include <memory>
int main() {
std::unique_ptr<int> ptr1 = std::make_unique<int>(10); // 동적 메모리 관리
std::cout << "Value: " << *ptr1 << std::endl;
// std::unique_ptr은 복사 불가능
// std::unique_ptr<int> ptr2 = ptr1; // 컴파일 오류
// 소유권 이전 (std::move)
std::unique_ptr<int> ptr2 = std::move(ptr1);
if (!ptr1) {
std::cout << "ptr1 is null after move." << std::endl;
}
std::cout << "Value from ptr2: " << *ptr2 << std::endl;
return 0;
}
출력
Value: 10
ptr1 is null after move.
Value from ptr2: 10
#include <iostream>
#include <memory>
int main() {
std::shared_ptr<int> ptr1 = std::make_shared<int>(20); // 동적 메모리 관리
std::cout << "Value: " << *ptr1 << ", Use count: " << ptr1.use_count() << std::endl;
std::shared_ptr<int> ptr2 = ptr1; // 공유 소유권
std::cout << "After sharing, Use count: " << ptr1.use_count() << std::endl;
ptr2.reset(); // ptr2 소유권 포기
std::cout << "After reset, Use count: " << ptr1.use_count() << std::endl;
return 0;
}
출력
Value: 20, Use count: 1
After sharing, Use count: 2
After reset, Use count: 1
참조 카운팅으로 인해 오버헤드가 발생.
shared_ptr의 Reference count를 관리하기 위해 매번 증가/감소 연산이 일어남.unique_ptr 에 비해 더 많은 비용(오버헤드)을 발생시킴.순환 참조(Circular Reference) 문제 발생 가능:
shared_ptr 객체가 서로를 참조하면 참조 카운트가 0이 되지 않아 메모리 누수 발생#include <iostream>
#include <memory>
struct B; // 전방 선언
struct A {
std::shared_ptr<B> b_ptr; // A가 B를 참조
~A() { std::cout << "A destroyed\\n"; }
};
struct B {
std::shared_ptr<A> a_ptr; // B가 A를 참조
~B() { std::cout << "B destroyed\\n"; }
};
int main() {
auto a = std::make_shared<A>(); // A 생성, 참조 카운트: 1
auto b = std::make_shared<B>(); // B 생성, 참조 카운트: 1
a->b_ptr = b; // A가 B를 참조, B의 참조 카운트: 2
b->a_ptr = a; // B가 A를 참조, A의 참조 카운트: 2
// 지역 변수 a와 b가 스코프를 벗어남.
// a와 b 자체의 참조 카운트는 감소하지만, 서로를 참조하고 있으므로:
// a->b_ptr이 b를 유지하므로 b의 참조 카운트는 1.
// b->a_ptr이 a를 유지하므로 a의 참조 카운트는 1.
// 결과적으로 참조 카운트가 절대 0이 되지 않으므로 메모리 누수 발생.
return 0;
}
#include <iostream>
#include <memory>
int main() {
std::shared_ptr<int> sharedPtr = std::make_shared<int>(30);
std::weak_ptr<int> weakPtr = sharedPtr; // 약한 참조
std::cout << "Shared use count: " << sharedPtr.use_count() << std::endl;
if (auto sp = weakPtr.lock()) { // 객체가 존재하면 shared_ptr로 변환
std::cout << "Value: " << *sp << std::endl;
}
sharedPtr.reset(); // shared_ptr가 소유권 포기
if (weakPtr.expired()) {
std::cout << "The object has been destroyed." << std::endl;
}
return 0;
}