之前的部落格《實現一個最基礎的智慧指針》裏實現了一個最簡單的使用參照計數方式的智慧指針。而UE4也有一套智慧指針的實現,可見《虛幻智慧指針庫 | Unreal Engine Documentation》中的介紹。
另外,我發現\Engine\Source\Runtime\Core\Public\Templates\SharedPointer.h
中的註釋也有很多有價值的資訊,例如設計意圖等,可以補充參考。(由於有些內容還沒有較深的理解,不敢妄加翻譯,先保留原文)
This is a smart pointer library consisting of shared references (TSharedRef), shared pointers (TSharedPtr),weak pointers (TWeakPtr) as well as related helper functions and classes. This implementation is modeled after the C++0x standard library’s shared_ptr as well as Boost smart pointers.
這個智慧指針庫包括:「共用參照(TSharedRef)」,「共用指針(TSharedPtr)」,「弱指針(TWeakPtr)」 以及相關的助手函數和助手類。這個庫是在C++0x標準庫的shared_ptr
以及Boost的智慧指針之後實現的。
Clean syntax. You can copy, dereference and compare shared pointers just like regular C++ pointers.
Prevents memory leaks. Resources are destroyed automatically when there are no more shared references.
Weak referencing. Weak pointers allow you to safely check when an object has been destroyed.
Thread safety. Includes 「thread safe」 version that can be safely accessed from multiple threads.
Ubiquitous. You can create shared pointers to virtually any type of object.
Runtime safety. Shared references are never null and can always be dereferenced.
No reference cycles. Use weak pointers to break reference cycles.
Confers intent. You can easily tell an object owner from an observer.
Performance. Shared pointers have minimal overhead. All operations are constant-time.
Robust features. Supports ‘const’, forward declarations to incomplete types, type-casting, etc.
Memory. Only twice the size of a C++ pointer in 64-bit (plus a shared 16-byte reference controller.)
TSharedRef - Non-nullable, reference counted non-intrusive authoritative smart pointer
TSharedPtr - Reference counted non-intrusive authoritative smart pointer
TWeakPtr - Reference counted non-intrusive weak pointer reference
-Use TSharedRef instead of TSharedPtr whenever possible – it can never be nullptr!
- You can call TSharedPtr::Reset() to release a reference to your object (and potentially deallocate)
- Use the MakeShareable() helper function to implicitly convert to TSharedRefs or TSharedPtrs
- You can never reset a TSharedRef or assign it to nullptr, but you can assign it a new object
- Shared pointers assume ownership of objects – no need to call delete yourself!
- Usually you should 「operator new」 when passing a C++ pointer to a new shared pointer
- Use TSharedRef or TSharedPtr when passing smart pointers as function parameters, not TWeakPtr
- The 「thread-safe」 versions of smart pointers are a bit slower – only use them when needed
- You can forward declare shared pointers to incomplete types, just how you’d expect to!
- Shared pointers of compatible types will be converted implicitly (e.g. upcasting)
- You can create a typedef to TSharedRef< MyClass > to make it easier to type
- For best performance, minimize calls to TWeakPtr::Pin (or conversions to TSharedRef/TSharedPtr)
- Your class can return itself as a shared reference if you derive from TSharedFromThis
- To downcast a pointer to a derived object class, to the StaticCastSharedPtr function
- ‘const’ objects are fully supported with shared pointers!
- You can make a ‘const’ shared pointer mutable using the ConstCastSharedPtr function
TSharedRef
就不用TSharedPtr
,因爲TSharedRef
可以保證值不是空的。TSharedPtr::Reset()
來解除對物體的參照(可能會導致物體的解構)。MakeShareable()
助手函數來隱式地將指針轉換爲TSharedRef
或TSharedPtr
。TSharedRef
重置爲空,但你可以將它指定爲一個新的物件。delete
了。new
來將一個C++指針傳遞給一個新的智慧指針。TSharedRef
或TSharedPtr
,而不是TWeakPtr
。TSharedRef< MyClass >
使用typedef
來讓表達更簡潔。TSharedFromThis
,你就可以return itself as a shared reference。StaticCastSharedPtr
函數。const
是完全支援的!ConstCastSharedPtr
函數來讓一個const共用指針mutable 。-Shared pointers are not compatible with Unreal objects (UObject classes)!
- Currently only types with that have regular destructors (no custom deleters)
- Dynamically-allocated arrays are not supported yet (e.g. MakeSharable( new int32[20] ))
- Implicit conversion of TSharedPtr/TSharedRef to bool is not supported yet
UObject
物件deleter
)TSharedPtr
或TSharedRef
轉換爲bool是不支援的。-Type names and method names are more consistent with Unreal’s codebase
- You must use Pin() to convert weak pointers to shared pointers (no explicit constructor)
- Thread-safety features are optional instead of forced
- TSharedFromThis returns a shared reference, not a shared pointer
- Some features were omitted (e.g. use_count(), unique(), etc.)
- No exceptions are allowed (all related features have been omitted)
- Custom allocators and custom delete functions are not supported yet
- Our implementation supports non-nullable smart pointers (TSharedRef)
- Several other new features added, such as MakeShareable and nullptr assignment
Pin()
操作來將一個弱指針轉換爲一個共用指針(沒有顯式的建構函式)。TSharedFromThis
返回的是一個共用參照,而不是共用指針。delete
函數都還不支援。TSharedRef
)MakeShareable
和賦空值。-std::shared_ptr (and even tr1::shared_ptr) is not yet available on all platforms
- Allows for a more consistent implementation on all compilers and platforms
- Can work seamlessly with other Unreal containers and types
- Better control over platform specifics, including threading and optimizations
- We want thread-safety features to be optional (for performance)
- We’ve added our own improvements (MakeShareable, assign to nullptr, etc.)
- Exceptions were not needed nor desired in our implementation
- We wanted more control over performance (inlining, memory, use of virtuals, etc.)
- Potentially easier to debug (liberal code comments, etc.)
- Prefer not to introduce new third party dependencies when not needed
std::shared_ptr
(甚至是tr1::shared_ptr
)都還沒有在所有平臺上都可用。MakeShareable
和賦空值。使用TSharedPtr
的目的,正如之前在《實現一個最基礎的智慧指針》所討論的,是想要用參照計數的方式來維護一個物件的銷燬。
class FTestClass
{
};
可以使用MakeShareable
將一個普通C++指針轉換爲智慧指針,這將意味着它指向的物件將會被智慧指針的機制 機製管理,在參照計數爲0時自動銷燬。
TSharedPtr<FTestClass> test = MakeShareable(new FTestClass());
需要注意的是,TSharedPtr
不能對UObject
類使用,因爲UObject
自己已經有GC的機制 機製了,不能再將其加入另一個記憶體管理的機制 機製。
雖然上面討論了弱指針TWeakPtr
,但我目前還沒有使用過它。
不過另外一種「弱指針」倒是經常使用:TWeakObjectPtr
。
使用它的目的是:有時候不確定一個UObject
是否已經被某種原因被GC掉了,將其包裹進TWeakObjectPtr
,則可用IsValid
方法來確定它是否還有效。
/**
* FWeakObjectPtr is a weak pointer to a UObject.
* It can return nullptr later if the object is garbage collected.
* It has no impact on if the object is garbage collected or not.
* It can't be directly used across a network.
*
* Most often it is used when you explicitly do NOT want to prevent something from being garbage collected.
*/
struct FWeakObjectPtr
FWeakObjectPtr
是一個針對UObject
的弱指針/**
* TWeakObjectPtr is the templated version of the generic FWeakObjectPtr
*/
template<class T, class TWeakObjectPtrBase>
TWeakObjectPtrBase
就是FWeakObjectPtr
的模板版本。
/**
* Test if this points to a live UObject
* @param bEvenIfPendingKill if this is true, pendingkill objects are considered valid
* @param bThreadsafeTest if true then function will just give you information whether referenced
* UObject is gone forever (return false) or if it is still there (return true, no object flags checked).
* @return true if Get() would return a valid non-null pointer
*/
FORCEINLINE bool IsValid(bool bEvenIfPendingKill, bool bThreadsafeTest = false) const
{
return TWeakObjectPtrBase::IsValid(bEvenIfPendingKill, bThreadsafeTest);
}
/**
* Test if this points to a live UObject. This is an optimized version implying bEvenIfPendingKill=false, bThreadsafeTest=false.
* @return true if Get() would return a valid non-null pointer
*/
FORCEINLINE bool IsValid(/*bool bEvenIfPendingKill = false, bool bThreadsafeTest = false*/) const
{
return TWeakObjectPtrBase::IsValid();
}
IsValid
可以檢測一個UObject
是否「活着」bEvenIfPendingKill
:如果是true,則pendingkill
的物件將被視爲有效,預設false。bThreadsafeTest
:if true then function will just give you information whether referenced UObject is gone forever (return false) or if it is still thereGet()
能得到一個非空且有效的指針。當然,TWeakObjectPtr
只能和UObject
類配合,否則便會報錯:
error C2338: TWeakObjectPtr can only be constructed with UObject types