포인터처럼 동작하지만 스스로 메모리를 관리하기 때문에 메모리 누수를 방지하고 메모리 관리의 복잡성을 줄여주는 C++의 특별한 클래스 타입
스마트 포인터는 C++에서 제공하는 포인터의 한 형태로, 포인터가 가리키는 메모리를 자동으로 해제하는 역할을 한다.
일반적으로 변수에 동적 메모리를 할당하면 그 메모리를 직접 해제해야한다. 그렇지 않으면 메모리 누수가 발생하게 되고, 이는 프로그램의 성능을 저하시킬 수 있을 뿐더러, 해제를 했다 하더라도 그 메모리를 다시 사용하려고 하는 '잘못된 해제(dangling reference)'문제를 발생시킬 가능성도 있다.
이러한 문제를 해결하기 위한 것이 "스마트 포인터(smart pointer)"로, 객체 생성 시 사용했던 동적 메모리 또는 시스템 자원을 소멸 시 자동으로 소멸할 수 있는 메커니즘을 제공함으로써 범위를 벗어난 변수는 스택에서 제거되며, 객체의 파괴자가 호출되어 자신이 사용하던 자원을 알아서 정리하여 메모리 누수를 방지해준다.
void main() {
double* rate = new double; // 포인터 변수 생성 및 new 연산자로 8바이트 힙메모리 생성
// 선언 시 사용하는 *는 rate가 포인터 변수라는 것을 알림
*rate = 3.14;
// 포인터변수가 가리키는 실제 메모리 주소에 들어있는 값을 가리키는 *
cout << *rate << endl;
delete rate;
}
위 예제 코드에서 rate 변수는 동적으로 생성한 실수형 변수의 메모리를 저장하는 포인터 변수이다.
rate 변수의 동적 메모리를 헤재하는 delete 수행을 주석 처리하면 rate 변수는 종료 시에 자동으로 메모리가 소멸되지만, 이 변수가 가리키는 주소 메모리는 자동으로 해제되지 않는다.

즉, 메모리 누수(Memory Leak)가 발생한다. 이렇듯, 동적으로 할당된 메모리는 이름이 없으므로 포인터를 잃어버리면 참조할 수 없어 해제가 어렵게 되기 때문에 스마트 포인터를 통해 이러한 문제를 방지한다.
template<typename T> class auto_ptr
포인터가 가리키는 대상체 타입 T를 인수로 받아 T*형의 포인터를 관리하며, 생성자로 전달한 포인터는 소멸자에서 delete로 해제하므로 포인터 뿐만 아니라 포인터가 가리키는 메모리도 자동으로 해제된다.
#include<iostream>
#include<memory>
void main() {
auto_ptr<double> rate(new double);
*rate = 3.14;
cout << *rate << endl;
}
위 코드에서 rate는 auto_ptr의 객체이다. 그런데, 원래 우리가 아는 포인터 클래스에서는 rate는 포인터 변수였다. 여기서 rate가 포인터 변수가 아닌 객체라면 new double로 생성한 포인터 변수는 어디에 있을까?
이건 auto_ptr의 내부로 들어가면 알 수 있다.
auto_ptr의 내부 구조
template <class _Ty>
class auto_ptr { // wrap an object pointer to ensure destruction
public:
using element_type = _Ty;
explicit auto_ptr(_Ty* _Ptr = nullptr) noexcept : _Myptr(_Ptr) {}
auto_ptr(auto_ptr& _Right) noexcept : _Myptr(_Right.release()) {}
auto_ptr(auto_ptr_ref<_Ty> _Right) noexcept {
_Ty* _Ptr = _Right._Ref;
_Right._Ref = nullptr; // release old
_Myptr = _Ptr; // reset this
}
~~ 중간 생략~~
~auto_ptr() noexcept {
delete _Myptr;
}
auto_ptr의 내부구조 코드를 보면 결국 new double로 생성한 객체에 대한 주소값을 가리키는 포인터 변수는 rate이 아닌 내부의 _Myptr변수 인 것을 알 수 있다.
또한, 내부 코드에서 이미 소멸자를 통해 main()함수가 끝나는 시점에 해당 포인터 변수를 delete함으로써, 메모리를 해제하고 있음을 알 수 있다.
따라서, 위 코드에서 생성한 rate를 따로 delete해주지 않아도 되는 것이며, 만약 따로 delete를 선언하면 에러가 발생하는 이유이기도 하다.
template <class T>
class MySmartPointer {
private:
T* p;
public:
MySmartPointer(T* sp) {
this->p = sp;
};
~MySmartPointer() { delete this->p; }
};
void main() {
MySmartPointer<string> str(new string("test"));
}
여기서 "test"라는 데이터를 가진 str객체를 생성할 때, 해당 데이터의 메모리 주소값은 sp가 받는다. 그런데 sp는 멤버함수에서 this->p를 받고 있다. 결과적으로 "test"라는 데이터의 주소값을 받고있는 것은 p인 것이고, 그래서 소멸자에서 delete this->p로 메모리를 str 종료 시점에서 자동 삭제하고 있는 것이다.
boost:shared_ptr로 C++ 표준 라이브러리가 아닌 boost에서 만든 스마트 포인터로 auto_ptr의 단점을 보완하기 위해 생겨난 스마트포인터이다. 사용 형태는 auto_ptr과 동일하다.