delete 메모리 해제를 안해도 되는 편리함
자동NULL, 메모리릭 방지 등 버그를 줄이기 위해서 사용
언리얼 오프젝트가 되어있다면, 그것은 GC가 관리를 한다.
해지 명령을 내려도 바로 해지되지 않고 GC 시스템에 의해 회수된다 (자세한 건 GC 파트에서)
https://docs.unrealengine.com/en-US/Programming/UnrealArchitecture/SmartPointerLibrary/index.html
Unreal Smart Pointer
The Unreal Smart Pointer Library is a custom implementation of C++11 smart pointers designed to ease the burden of memory allocation and tracking.
This implementation includes the industry standard Shared Pointers, Weak Pointers, and Unique Pointers.
It also adds Shared References which act like non-nullable Shared Pointers.
These classes cannot be used with the UObject system
because Unreal Objects use a separate memory-tracking system that is better-tuned for game code.
언리얼 스마트 포인터 라이브러리는 메모리 할당과 트래킹의 부담을 줄이기 위해 디자인된,
C++ 11 커스텀 스마트 포인터이다
구현에는 공유포인터, 약포인터, 유니트포인터가 있다
최근 추가된 공유레퍼런스는 null이 값에만 사용할 수 있는 공유포인터랑 같은 역활을 한다.
이런 클래스들은 언리얼 시스템과 같이 사용할 수가 없는데, 언리얼 오브젝트는 별도의 메모리트래킹 시스템으로
더 좋게 게임코드 사용할 수 있기 떄문이다.
Smart Pointer Types
1. Shared Pointers (TSharedPtr)
침범형(non-intrusive), 레퍼런스가 카운팅되는 편리한 유형의 스마트 포인터
A Shared Pointer owns the object it references,
indefinitely preventing deletion of that object, and ultimately handling its deletion
when no Shared Pointer or Shared Reference (see below) references it.
A Shared Pointer can be empty, meaning it doesn't reference any object.
Any non-null Shared Pointer can produce a Shared Reference to the object it references.
공유포인터는 객체를 참조하며,
삭제를 방지하다가, 더이상 공유포인터 또는 공유레퍼런스가 없을떄(참조카운트가 0)일떄 삭제된다
공유포인터가 비었다는 건, 참조하는 객체가 없을 수 있다. (값이 없을 수 도 있음)
null이 아닌 공유포인터는 참조하는 객체에 대한 공유레퍼런스를 생성 있다.
2. Shared References (TSharedRef)
null 가능하지 않은 공유 포인터
A Shared Reference acts like a Shared Pointer, in the sense that it owns the object it references.
They differ with regard to null objects; Shared References must always reference a non-null object.
Because Shared Pointers don't have that restriction, a Shared Reference can always be converted to a Shared Pointer, and that Shared Pointer is guaranteed to reference a valid object.
Use Shared References when you want a guarantee that the referenced object is non-null,
or if you want to indicate shared object ownership.
공유레퍼런스는 참조하는 객체를 소유(?참조?)한다는 점에서 공유포인터랑 비슷하다.
그러나 공유참조는, 항상 null이 아닌 객체를 참조해야 한다는 점이 다르다. (항상 값이 있어야 함)
왜냐하면 공유포인터는 이러한 제한이 없으므로, 공유레퍼런스는 항상 공유포인터로 변활 수 있으므로,
공유포인터는 유요한 객체를 참조하도록 보장된다.(값이 들어있다, 간단히 참조라서 값이 있어야 함)
공유레퍼런스는 null이 아닌 것을 보장하거나, 공유객체 소유권(?)을 나타낼 떄 사용한다,
※ 공유포인터는 null일 수도 있음, null이 아니면 공유레퍼런스 생성가능
※ 공유레퍼런스는 항상 null이 아닌 객체를 참조해야함, 항상 값이 있으므로, 공유포인터로 변경가능
※ 공유 레퍼런스는 항상 유효하기 때문에 공유 포인터와는 달리 IsValid() 메서드조차 없음
3. Weak Pointers (TWeakPtr)
오브젝트로의 약 레퍼런스 (weak reference)를 보관하는 포인터
Weak Pointers are similar to Shared Pointers,
but do not own the object they reference, and therefore do not affect its lifecycle.
This property can be very useful, as it breaks reference cycles,
but it also means that a Weak Pointer can become null at any time, without warning.
For this reason, a Weak Pointer can produce a Shared Pointer to the object it references,
ensuring programmers safe access to the object on a temporary basis.
약포인터는 공유포인터랑 유사하다
그러나 참조한 객체 소유하지 않으므로, 라이프사이클(액터 수명주기?)에 영향을 주지 않는다.
약포인터는 레퍼런스 사이클이 없어졋을때, 경고없이 NULL이 될 수 있어서 유용 할 수 있다.
(예기치 못하게 비워질 수도, 레퍼런스 사이클을 깨는 데 사용)
이런 이유는 약포인터는 객체에 대한 공유포인터를 생성하고, 개체에 안전하게 접근 할수 있게 한다.
(NULL이 아닌건 없음)
4. Unique Pointers (TUniquePtr)
고유 소유권을 가지는 포인터
A Unique Pointer solely and explicitly owns the object it references.
Since there can only be one Unique Pointer to a given resource, Unique Pointers can transfer ownership, but cannot share it. Any attempts to copy a Unique Pointer will result in a compile error.
When a Unique Pointer is goes out of scope, it will automatically delete the object it references.
고유 포인터는 객체를 명시적으로 소유한다
주어진 리소스에 하나의 고유포인터고 소유권이 존재하는데, 고유 포인터는 소유권을 이전 할 수 있지만,
공유를 할 수없다. 고유포인터를 복사할려고 하면, 컴파일 에러가 발생할 것이다
고유포인터는 객체에 소유권을 벗어나거나 없어지면, 자동으로 소멸한다.
Benefits of Smart Pointers
Prevents memory leaks (메모리릭 방지)
Smart Pointers (other than Weak Pointers) automatically delete objects when there are no more shared references.
(스마트포인터는 공유레퍼런스가 없을떄 자동으로 소멸한다)
Weak referencing (약레퍼런싱)
Weak Pointers break reference cycles and prevent dangling pointers.
(약포인터로 언제 오브젝트가 소멸되었는지를 안전하게 검사할 수 있다.)
Optional Thread safety (스레드 안정성)
The Unreal Smart Pointer Library includes thread-safe code that manages reference counting across multiple threads. Thread safety can be traded out for better performance if it isn’t needed.
(여러 스레드에서 안전하게 접근할 수 있는 "thread safe" 버전이 포함되어 있다.)
(스데르 안정성이 필요 없는 경우에 성능향상을 위해서 교환할 수 있다)
Runtime safety (런타임 안정성)
Shared References are never null and can always be dereferenced.
Confers intent (명확한 의도)
You can easily tell an object owner from an observer.
(오브젝트 owner 와 observer 를 쉽게 구분할 수 있다.)
Memory (메모리)
Smart Pointers are only twice the size of a C++ pointer in 64-bit (plus a shared 16-byte reference controller).
The exception to this is Unique Pointers, which are the same size as C++ pointers.
[64 비트의 C++ 포인터 크기에 비해 두 배밖에 안된다 (추가로 공유 16 바이트 레퍼런스 컨트롤러)]
Helper Classes and Functions
스마트 포인터를 더욱 쉽고 직관적으로 사용할 수 있도록, 클래스와 함수 형태의 헬퍼가 다수 라이브러리에 제공
Helper | Description |
Classes |
|
TSharedFromThis |
"this" 에서 TSharedRef 를 구하려면 여기에서 클래스를 파생시키면 된다 |
Functions |
|
MakeShared |
C++ 포인터로 부터 공유포인터를 만든다 MakeShared |
StaticCastSharedRef and |
정적인 형변환 유틸리티 함수로, 보통 파생 유형으로 내림변환(downcast)하는 데 사용 |
ConstCastSharedRef |
'const' 스마트 포인터를 'mutable' 스마트 포인터로 변환 |
Smart Pointer Implementation Details
언리얼 스마트 포인터 라이브러리에 구현되어 있는 여러 유형의 스마트 포인터는
모두 퍼포먼스, 메모리 등의 측면에서 일반적인 특징을 공유한다
퍼포먼스(Speed)
항상 스마트 포인터를 사용할 떄는 퍼포먼스를 고려해야 한다.
일반적으로 꽤 빠릅니다만, 아무 데나 쓰라는 용도는 아니다.
특정 하이 레벨 시스템이나 툴 프로그래밍에는 좋지만, 로우 레벨 엔진/렌더링 패스에는 그다지 적합하지 않다.
스마트 포인터의 일반적인 퍼포먼스 장점:
-
모든 연산이 고정비(constant-time) 입니다.
-
스마트 포인터 레퍼런스 해제가 C++ 포인터만큼 빠릅니다.
-
스마트 포인터를 복사한다고 절대 메모리가 할당되지 않습니다.
-
Thread Safe 버전은 교착상태에 빠지지 않습니다(lock-free).
스마트 포인터의 퍼포먼스 단점:
-
스마트 포인터는 C++ 포인터 보다 생성과 복사에 부하가 걸린다
-
레퍼런스 카운트를 유지하면서 작업을 추가해야 한다
-
스마트 포인터는 C++ 포인터보다 메모리 사용한다.
- 레퍼런스 컨터롤러는 2번째 힙할당이 있다.
MakeShareable 대신 MakeShared 사용하면 2번쨰 할당을 피할 수 있으며, 성능을 향상 시킬수 있다
Intrusive Accessors
Shared pointers are non-intrusive, which means the object does not know whether or not a Smart Pointer owns it. This is usually acceptable, but there may be cases in which you want to access the object as a Shared Reference or Shared Pointer.
To do this, derive the object’s class from TSharedFromThis, using the object’s class as the template parameter.
TSharedFromThis provides two functions, AsShared and SharedThis, that can convert the object to a Shared Reference (and from there, to a Shared Pointer).
This can be useful with class factories that always return Shared References, or when you need to pass your object to a system that expects a Shared Reference or Shared Pointer.
AsShared will return your class as the type originally passed as the template argument to TSharedFromThis, which may be a parent type to the calling object, while SharedThis will derive the type directly from this and return a Smart Pointer referencing an object of that type.
The following example code demonstrates both functions:
class FRegistryObject;
class FMyBaseClass: public TSharedFromThis<FMyBaseClass>
{
virtual void RegisterAsBaseClass(FRegistryObject* RegistryObject)
{
// Access a shared reference to 'this'.
// We are directly inherited from <TSharedFromThis> , so AsShared() and SharedThis(this) return the same type.
TSharedRef<FMyBaseClass> ThisAsSharedRef = AsShared();
// RegistryObject expects a TSharedRef<FMyBaseClass>, or a TSharedPtr<FMyBaseClass>. TSharedRef can implicitly be converted to a TSharedPtr.
RegistryObject->Register(ThisAsSharedRef);
}
};
class FMyDerivedClass : public FMyBaseClass
{
virtual void Register(FRegistryObject* RegistryObject) override
{
// We are not directly inherited from TSharedFromThis<>, so AsShared() and SharedThis(this) return different types.
// AsShared() will return the type originally specified in TSharedFromThis<> - TSharedRef<FMyBaseClass> in this example.
// SharedThis(this) will return a TSharedRef with the type of 'this' - TSharedRef<FMyDerivedClass> in this example.
// The SharedThis() function is only available in the same scope as the 'this' pointer.
TSharedRef<FMyDerivedClass> AsSharedRef = SharedThis(this);
// RegistryObject will accept a TSharedRef<FMyDerivedClass> because FMyDerivedClass is a type of FMyBaseClass.
RegistryObject->Register(ThisAsSharedRef);
}
};
class FRegistryObject
{
// This function will accept a TSharedRef or TSharedPtr to FMyBaseClass or any of its children.
void Register(TSharedRef<FMyBaseClass>);
};
Casting
You can cast Shared Pointers (and Shared References) through several support functions included in the Unreal Smart Pointer Library. Up-casting is implicit, as with C++ pointers.
You can const cast with the ConstCastSharedPtr function, and static cast (often to downcast to derived class pointers) with StaticCastSharedPtr.
Dynamic casting is not supported, as there is no run-type type information (RTTI); static casting should be used instead, as in the following code:
언리얼 스마트 포인터 라이브러리에 포함 된 여러 지원 기능을 통해 공유 포인터 (+ 공유 참조)를 사용할 수 있습니다.
올림변환(up-casting)은 C++ 포인터와 마찬가지로 묵시적(지정하지 않아도 알아서 해줌)이다.
const cast 할 수 있는 ConstCastSharedPtr 기능과 static cast(다운캐스트) 할 수 있는 StaticCastSharedPtr
Dynamic 형변환은 지원되지 않되고, (no RTTI)가 안됨. 대신 위의 static 형변환을 사용해야 한다
Thread Safety
보통의 공유 포인터는 싱글 스레드에서만 안전하게 접근할 수 있습니다.
멀티 스레드에서 접근하도록 해야 한다면, Thread Safe 버전 포인터 클래스를 사용하야 한다
-
TSharedPtr<T, ESPMode::ThreadSafe>
-
TSharedRef<T, ESPMode::ThreadSafe>
-
TWeakPtr<T, ESPMode::ThreadSafe>
-
TSharedFromThis<T, ESPMode::ThreadSafe>
이 버전은 레퍼런스 카운팅을 개별적으로(atomic) 하기 때문에 약간 느리지만,
일반 C++ 포인터와 작동하는 방식은 거의 같다:
-
읽기와 복사는 항상 스레드 안전합니다.
-
쓰기/리셋의 안전을 위해서는 반드시 동기화시켜야 합니다.
※ 포인터가 둘 이상의 스레드에서 접근될 일이 절대 없는 게 확실한 경우, Thread Safe 버전을 사용하지 마시오.
Tips and Limitations
- TSharedRef or TSharedPtr 를 사용해서, 파라미터를 함수를 넘길떄는 피하고. 되도록 피해라,
레퍼런스 해제 및 레퍼런스 카운팅을 통해 오버헤드 가 발생 할 수 있기 떄문.
그래서 전달할떄는 참조된 객체를 const &로 전달 하는게 좋다 - C++ 포인터와는 달리 공유 포인터는 memcpy 가 불가능하므로, 공유 포인터 배열을 사용할 때는 이 점을 고려하시기 바랍니다
- 스마트 포인터를 함수 파라미터로 전달할 때는 TWeakPtr 가 아닌, TSharedRef 나 TSharedPtr 를 사용
- 공유 포인터를 불완전한 유형으로 전달 선언 할 수 있다
- 공유 포인터는 Unreal 객체 ( UObject및 파생 클래스)와 호환되지 안된다.
엔진은 관리를 위해 별도의 메모리 관리 시스템 ( 객체 처리 문서 참조 )이 UObject있으며,
두 시스템은 서로 겹치지 않는다.
'Unreal > Concept' 카테고리의 다른 글
언리얼 메타휴먼 애니메이터 (0) | 2023.08.29 |
---|---|
unreal - code & blueprint (0) | 2020.12.08 |
FArchive 아카이브, << 연산자 (1) | 2019.05.31 |
델리게이트 + 종류 및 함수 + 시그니처 + 바인딩 (0) | 2019.05.30 |
UWorld (0) | 2019.05.30 |