内存大小
TSharedRef维护一个指针对象和一个引用计数控制器, 在 64 位系统中只有 C++ 指针大小的两倍(加上一个共享的 16 字节引用控制器)。
template< class ObjectType, ESPMode InMode >
class TSharedRef
{
ObjectType* Object;
SharedPointerInternals::FSharedReferencer< Mode > SharedReferenceCount;
}
template< ESPMode Mode >
class FSharedReferencer
{
TReferenceControllerBase<Mode>* ReferenceController;
}
template <ESPMode Mode>
class TReferenceControllerBase
{
using RefCountType = std::conditional_t<Mode == ESPMode::ThreadSafe, std::atomic<int32>, int32>;
RefCountType SharedReferenceCount{1};
RefCountType WeakReferenceCount{1};
}
enum class ESPMode : uint8
{
/** Forced to be not thread-safe. */
NotThreadSafe = 0,
/** Thread-safe, never spin locks, but slower */
ThreadSafe = 1
};
引用计数
- SharedReferenceCount默认是1,因为创建即为1次了。
- Copy constructor 计数会+1
- Move constructor 计数转移给新的,然后自己计数清空
- Destructor 计数-1,如何计数为0了调用DestroyObject
- Assignment operator 新的+1,自己-1
- Move assignment operator 自己接受新的计数,自己原来持有那份老的-1
替换引用
//Assignment operator replaces this shared reference with the specified shared reference.
FORCEINLINE TSharedRef& operator=( TSharedRef const& InSharedRef )
{
TSharedRef Temp = InSharedRef;
::Swap(Temp, *this);
return *this;
}
FORCEINLINE TSharedPtr& operator=( TSharedPtr&& InSharedPtr )
{
if (this != &InSharedPtr)
{
Object = InSharedPtr.Object;
InSharedPtr.Object = nullptr;
SharedReferenceCount = MoveTemp(InSharedPtr.SharedReferenceCount);
}
return *this;
}
template <typename T>
struct TUseBitwiseSwap
{
// We don't use bitwise operations for 'register' types because this will force them into memory and be slower.
enum { Value = !(std::is_enum_v<T> || std::is_pointer_v<T> || std::is_arithmetic_v<T>) };
};
/**
* Swap two values. Assumes the types are trivially relocatable.
*/
template <typename T>
inline void Swap(T& A, T& B)
{
if constexpr (TUseBitwiseSwap<T>::Value)
{
TTypeCompatibleBytes<T> Temp;
*(TTypeCompatibleBytes<T>*)&Temp = *(TTypeCompatibleBytes<T>*)&A;
*(TTypeCompatibleBytes<T>*)&A = *(TTypeCompatibleBytes<T>*)&B;
*(TTypeCompatibleBytes<T>*)&B = *(TTypeCompatibleBytes<T>*)&Temp;
}
else
{
T Temp = MoveTemp(A);
A = MoveTemp(B);
B = MoveTemp(Temp);
}
}
/**
* MoveTemp will cast a reference to an rvalue reference.
* This is UE's equivalent of std::move except that it will not compile when passed an rvalue or
* const object, because we would prefer to be informed when MoveTemp will have no effect.
*/
template <typename T>
UE_INTRINSIC_CAST FORCEINLINE constexpr std::remove_reference_t<T>&& MoveTemp(T&& Obj) noexcept
{
using CastType = std::remove_reference_t<T>;
// Validate that we're not being passed an rvalue or a const object - the former is redundant, the latter is almost certainly a mistake
static_assert(std::is_lvalue_reference_v<T>, "MoveTemp called on an rvalue");
static_assert(!std::is_same_v<CastType&, const CastType&>, "MoveTemp called on a const object");
return (CastType&&)Obj;
}
限制
- 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. MakeShareable( new int32[20] ))