new, delete 와 스마트 포인터 간 어떤 차이가 있을까 ?
메모리 누수 확인
CRT 라이브러리를 통해 메모리 누수를 확인해 볼 수 있다.
#include <crtdbg.h>
#include <iostream>
int main() {
int *a = new int[5];
std::cout << "a: " << a << std::endl;
_CrtDumpMemoryLeaks();
return 0;
}
위 코드에서 a에 메모리를 할당해주고 해제를 해주지 않게 되면 crt 라이브러리에서 어떤 데이터가 해제 안되었는지 알려준다.
new, delete
#include <crtdbg.h>
#include <iostream>
int main() {
int *a = new int[5];
delete[] a;
_CrtDumpMemoryLeaks();
return 0;
}
위 코드와 같이 정상적으로 메모리 할당 및 해제가 이루어 질때는 메모리 누수가 일어나지 않는다. 그러나, 할당과 해제 사이에 예외 상황이 생긴다면 어떻게 될까?
#include <crtdbg.h>
#include <iostream>
void thrower() { throw 1; }
void f() {
int *a = new int[5];
thrower();
delete[] a;
}
int main() {
try {
f();
}
catch (int) {
std::cout << "Exception caught" << std::endl;
}
return 0;
}
위와 같이 해제 이전에 예외가 발생하는 케이스를 만들어봤다.
메모리 누수가 발생한다. 이렇게 메모리를 new로 할당해주면 delete로 해제만 하면 되는 것이 아니라 그 사이에 발생할 수 있는 예외들까지 모두 고려해야 하기 때문에 매우 복잡하다. 그래서 RAII의 개념을 적용한 스마트 포인터가 사용된다. C++에서는 heap에 할당 된 자원은 위와 같이 명시적으로 해제하지 않으면 해제되지 않지만, stack에 할당 된 자원은 자신의 scope가 끝나면 메모리가 해제되고 destructor가 불린다는 원리를 이용한 것이다.
스마트 포인터
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#include <iostream>
void thrower() { throw 1; }
class Resource {
int* data;
public:
Resource() : data(new int(5)) { std::cout << "Resource acquired" << std::endl; }
~Resource() {
delete data;
std::cout << "Resource destroyed" << std::endl;
}
};
void f() {
std::unique_ptr<Resource> res(new Resource);
thrower();
}
int main() {
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
try {
f();
}
catch (int) {
std::cout << "Exception caught" << std::endl;
}
return 0;
}
스마트 포인터를 적용해서 소멸자가 불리는지 확인하기 위해 Resource 객체를 만들어서 위와 같이 코드를 만들었다.
throw가 발생해서 함수를 벗어나게 되더라도 f 함수의 스코프를 벗어나기 때문에 Resource 객체 메모리가 해제되는 것을 확인할 수 있다.
'개발 > C++' 카테고리의 다른 글
QNX 에서 Google Test 돌리기 (0) | 2023.12.22 |
---|---|
C++ 에서 Google Test 사용 (0) | 2023.12.22 |