do_something
에서 소멸자를 호출하지 않아 생성된 객체를 가리키던pa
는 메모리에서 사라지게 됨Heap
어딘가에 클래스 A
의 객체가 남아있지만, 그 주소 값을 가지고 있는 포인터는 메모리 상에 존재하지 않게 됨#include <iostream>
class A {
int *data;
public:
A() {
data = new int[100];
std::cout << "자원을 획득함!" << std::endl;
}
~A() {
std::cout << "소멸자 호출!" << std::endl;
delete[] data;
}
};
void do_something() { A *pa = new A(); }
int main() {
do_something();
// 할당된 객체가 소멸되지 않음!
// 즉, 400 바이트 (4 * 100) 만큼의 메모리 누수 발생
}
pa
는 객체가 아니기 때문에 소멸자가 호출되지 않음, 그렇다면 그 대신 pa
를 일반적인 포인터가 아닌 포인터 객체로 만들어서 자신이 소멸될 때 자신이 가리키고 있는 데이터도 같이 delete
시키는 것.smart pointer
delete
시키는 double free 버그가 발생가능unique_ptr
은 복사 생성자가 명시적으로 삭제되었기 때문에 복사 생성자를 사용할 수 없음A(const A& a) = delete;
#include <iostream>
#include <memory>
class A {
int *data;
public:
A() {
std::cout << "자원을 획득함!" << std::endl;
data = new int[100];
}
void some() { std::cout << "일반 포인터와 동일하게 사용가능!" << std::endl; }
~A() {
std::cout << "자원을 해제함!" << std::endl;
delete[] data;
}
};
void do_something() {
std::unique_ptr<A> pa(new A());
pa->some();
}
int main() { do_something(); }
자원을 획득함!
일반 포인터와 동일하게 사용가능!
자원을 해제함!
std::unique_ptr<A> pb = std::move(pa);
pa
가 가리키는 객체 확인: nullptr
pa.get();
unique_ptr은 그냥 함수에 레퍼런스 전달하듯이 사용하면 소유권이라는 의미를 망각한 채 단순히 포인터의 wrapper로 사용하는 것에 불과하게 됨
따라서 레퍼런스로 사용하기 위해 원래 포인터의 주소값을 전달해주자
void do_something(A* ptr) { ptr->do_sth(3); }
int main() {
std::unique_ptr<A> pa(new A());
do_something(pa.get());
}
unique_ptr
을 간단히 만들 수 있는 std::make_unique
함수를 제공#include <iostream>
#include <memory>
class Foo {
int a, b;
public:
Foo(int a, int b) : a(a), b(b) { std::cout << "생성자 호출!" << std::endl; }
void print() { std::cout << "a : " << a << ", b : " << b << std::endl; }
~Foo() { std::cout << "소멸자 호출!" << std::endl; }
};
int main() {
auto ptr = std::make_unique<Foo>(3, 5);
ptr->print();
}
생성자 호출!
a : 3, b : 5
소멸자 호출!
unique_ptr
은 복사생성자가 없기 때문에 vector
컨테이너를 사용할 때 push_back
함수를 사용한다면 컴파일 에러가 발생vector
안으로 이동시켜 주어야 함int main() {
std::vector<std::unique_ptr<A>> vec;
std::unique_ptr<A> pa(new A(1));
vec.push_back(std::move(pa)); // push_back의 우측값 레퍼런스를 받는 버전이 오버로딩되어 실행됨
}