位运算做标记的好处
很多底层的东西都喜欢用 对1位移N位来做枚举或标记,是因为这样可以同时保存多个状态进这个标记
- 以这个枚举为例(虚幻源码中垃圾回收对象的标记枚举,这里把位移n位改为了1,2,3,4…) - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14- enum class EInternalObjectFlags : int32 
 {
 None = 0,
 // All the other bits are reserved, DO NOT ADD NEW FLAGS HERE!
 ReachableInCluster = 1 << 1, /// External reference to object in cluster exists
 ClusterRoot = 1 << 2, ///< Root of a cluster
 Native = 1 << 3, ///< Native (UClass only).
 Async = 1 << 4, ///< Object exists only on a different thread than the game thread.
 AsyncLoading = 1 << 5, ///< Object is being asynchronously loaded.
 Unreachable = 1 << 6, ///< Object is not reachable on the object graph.
 PendingKill = 1 << 7, ///< Objects that are pending destruction (invalid for gameplay but valid objects)
 RootSet = 1 << 8, ///< Object will not be garbage collected, even if unreferenced.
 NoStrongReference = 1 << 9,
 };
- 初始化个变量 - 1 - EInternalObjectFlags Flags = EInternalObjectFlags::Native; //也就是Flags = 00010000 
- 假设有这几个接口 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25- FORCEINLINE void SetPendingKill() 
 {
 Flags |= int32(EInternalObjectFlags::PendingKill);
 }
 FORCEINLINE void ClearPendingKill()
 {
 Flags &= ~int32(EInternalObjectFlags::PendingKill);
 }
 FORCEINLINE bool IsPendingKill() const
 {
 return !!(Flags & int32(EInternalObjectFlags::PendingKill));
 }
 FORCEINLINE void SetRootSet()
 {
 Flags |= int32(EInternalObjectFlags::RootSet);
 }
 FORCEINLINE void ClearRootSet()
 {
 Flags &= ~int32(EInternalObjectFlags::RootSet);
 }
 FORCEINLINE bool IsRootSet() const
 {
 return !!(Flags & int32(EInternalObjectFlags::RootSet));
 }
- 状态改变过程 - SetPendingKill, Flags = 10010000,加入了PendingKill状态,此时有PendingKill和Native两种状态
- IsPendingKill, ret = 10010000 & 10000000 = 10000000 = true,判断是否有 PendingKill 状态
- ClearPendingKill, Flags = 10010000 & 0111111 = 00010000,清除了PendingKill状态,此时只有 NativeNative 状态
- 其他以此类推
 
- 作用场景 - 用于同一个标记Flag中需要保存多种状态,否者用普通的枚举1,2,3…就可以。