728x90
반응형
개요
이번 포스팅에서는 기본적인 C++의 스마트 포인터와 언리얼 엔진에서의 스마트 포인터에 대해 정리해보도록 하겠습니다.
C++ 스마트 포인터 (Unique, Shared, Weak)
스마트 포인터는 메모리 관리를 자동화해 메모리 누수를 방지하고 객체의 수명을 관리하는데 유용합니다.
Unique_ptr
- 단일 소유권을 가지는 스마트 포인터입니다.
- 소유권이 하나 뿐이므로, 복사가 불가 합니다.
- 객체가 더 이상 사용되지 않는 경우 소멸되어 자동으로 메모리가 해제됩니다.
#include <iostream>
// 스마트 포인터를 사용하기 위한헤더
#include <memory>
using namespace std;
class MyClass {
public:
MyClass() { std::cout << "MyClass 생성\n"; }
~MyClass() { std::cout << "MyClass 소멸\n"; }
void ShowMessage() { std::cout << "Hello, unique_ptr!\n"; }
};
int main() {
// 스마트 포인터 생성
unique_ptr<MyClass> ptr = std::make_unique<MyClass>();
ptr->ShowMessage();
// 소멸자는 main 함수 종료 시 자동 호출됩니다.
// * 더이상 사용되지않는 시점에 자동 소멸됩니다.
}
Shared_ptr
- 참조 횟수(Reference Count)를 기반으로 다중 소유권을 지원하는 스마트 포인터입니다.
- 참조하고 있는 마지막 포인터가 소멸할 때 자동으로 메모리가 해제됩니다.
#include <iostream>
#include <memory>
using namespace std;
class MyClass
{
public:
MyClass() { std::cout << "MyClass 생성\n"; }
~MyClass() { std::cout << "MyClass 소멸\n"; }
void ShowMessage() { std::cout << "Hello, shared_ptr!\n"; }
};
int main()
{
// 스마트 포인터 생성 (참조 횟수 : 1)
shared_ptr<MyClass> ptr1 = std::make_shared<MyClass>();
{
shared_ptr<MyClass> ptr2 = ptr1; // 참조 횟수 증가 (참조 횟수 : 2)
ptr2->ShowMessage();
}
// ptr2가 범위를 벗어나 참조 횟수 감소 (참조 횟수 : 1)
ptr1->ShowMessage();
// main 함수 종료 시 참조 횟수 감소 (참조 횟수 : 0)
// * 참조 횟수가 0이므로 자동 소멸합니다.
}
Weak_ptr
- 참조 횟수에 영향을 주지 않는 스마트 포인터입니다.
- shared_ptr과 함께 사용되며, 순환 참조 문제를 해결할 수 있습니다.
- shared_ptr을 사용해 메모리가 해제되었는지 확인 후 사용 가능합니다. (lock)
#include <iostream>
#include <memory>
using namespace std;
class MyClass
{
public:
MyClass() { std::cout << "MyClass 생성\n"; }
~MyClass() { std::cout << "MyClass 소멸\n"; }
void ShowMessage() { std::cout << "Hello, weak_ptr!\n"; }
};
int main()
{
// shared_ptr 생성 (참조 횟수 : 1)
shared_ptr<MyClass> ptr = std::make_shared<MyClass>();
// weak_ptr 생성 (ptr에 대한 참조 횟수 증가 X)
weak_ptr<MyClass> weakPtr = ptr;
if (shared_ptr<MyClass> tempPtr = weakPtr.lock())
{
tempPtr->ShowMessage();
} else {
std::cout << "객체가 이미 소멸되었습니다.\n";
}
}
순환 참조 예시
#include <iostream>
#include <memory>
class B; // 전방 선언
class A
{
public:
std::shared_ptr<B> ptrB;
A() { std::cout << "A created\n"; }
~A() { std::cout << "A destroyed\n"; }
};
class B
{
public:
std::shared_ptr<A> ptrA;
B() { std::cout << "B created\n"; }
~B() { std::cout << "B destroyed\n"; }
};
int main()
{
// 스마트 포인터 생성 (a, b : 참조 횟수 : 1)
auto a = std::make_shared<A>();
auto b = std::make_shared<B>();
// 스마트 포인터 복사 (a, b : 참조 횟수 : 2)
a->ptrB = b;
b->ptrA = a;
// a와 b는 범위를 벗어나도 순환 참조로 인해 참조 횟수가 0이 되지 않음
// * 즉, 순환 참조 발생으로 인해 A와 B가 파괴되지 않음
}
언리얼 스마트 포인터
언리얼 엔진에서 제공하는 스마트 포인터 라이브러리는 메모리 할당과 추적의 부담을 해소해주도록 C++ 11 스마트 포인터들의 커스텀 구현입니다.
스마트 포인터들은 갖고 있거나 참조하는 오브젝트의 생명 주기에 영향을 줄 수 있으며, 다른 스마트 포인터마다 오브젝트에 주는 제한사항과 효과도 달라집니다.
TUniquePtr
- C++의 unique_ptr과 유사하게 단일 소유권을 제공합니다.
- 기존과 동일하게 복사가 불가능하며, 범위(스코프)를 벗어나게 되면 참조하는 오브젝트가 자동 소멸합니다.
TSharedPtr
- C++의 shared_ptr과 유사하게 참조 횟수를 관리하여 다중 소유권을 지원합니다.
- 참조하는 TSharedPtr 또는 TSharedRef가 없을 경우 해당 오브젝트를 소멸시킵니다.
- TSharedPtr은 널 포인터로 초기화할 수 있고, 참조가 끊어진 경우에도 널(null)을 가질 수 있습니다.
TSharedRef
- TSharedRef는 참조 횟수 기반의 스마트 포인터로 TSharedPtr과 유사합니다.
- 반드시 유효한 객체를 참조해야 한다는 강제 조건이 존재합니다. (Null pointer 초기화 불가능)
- 즉, TSharedRef는 널 포인터를 허용하지 않으며, 객체가 항상 유효함을 보장합니다.
TWeakPtr
- TSharedPtr와 함께 사용되며, 순환 참조를 방지합니다.
- Pin 함수를 사용하여 실제 TSharedPtr로 변환한 뒤 사용 여부를 확인할 수 있습니다.
TSharedPtr와 TSharedRef의 관계 및 변환
TSharedPtr → TSharedRef 변환
- TSharedRef는 항상 유효한 객체를 참조해야 하므로 TSharedPtr에서 TSharedRef로 변환할 수 있습니다.
- 이때 TSharedPtr이 유효해야만 변환이 가능하며, 그렇지 않으면 에러가 발생합니다.
TSharedRef → TSharedPtr 변환
- TSharedRef에서 TSharedPtr로 변환은 간단합니다.
- TSharedRef 는 항상 유효하므로 널 체크 없이 TSharedPtr로 변환 가능합니다.
// TSharedPtr -> TSharedRef
TSharedPtr<MyClass> SharedPtr = MakeShared<MyClass>();
TSharedRef<MyClass> SharedRef = SharedPtr.ToSharedRef();
// TSharedRef -> TSharedPtr
TSharedPtr<MyClass> ConvertedPtr = SharedRef;
언리얼 엔진에서 스마트 포인터를 사용하는 이유
언리얼 엔진의 리플렉션 시스템은 객체 관리에 유용하지만 모든 상황에 대응하지는 못합니다.
다음과 같은 경우 스마트 포인터를 활용하는 것이 적합합니다.
- UObject를 상속받지 않은 클래스의 객체 메모리 관리
- 특정 객체의 수명을 코드에서 명확히 통제하고자 할 때
- 순환 참조 문제를 예방하고 메모리 누수를 방지하고자 할 때
- 레퍼런스 카운팅을 통해 객체를 안전하게 공유할 때
참고 자료
https://dev.epicgames.com/documentation/ko-kr/unreal-engine/smart-pointers-in-unreal-engine
728x90
반응형
'Game Programming > Unreal Engine' 카테고리의 다른 글
[Unreal Engine] Delegate (0) | 2024.10.30 |
---|---|
[Unreal Engine] DataAsset, Lazy Loading (0) | 2024.10.28 |
[Unreal Engine 5] AI Controller (0) | 2024.10.01 |
[Unreal Engine 5] FABRIK IK (0) | 2024.08.25 |
[Unreal Engine] 리플렉션 시스템, CDO (0) | 2024.07.26 |