位运算做标记的好处

很多底层的东西都喜欢用 对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));
    }
  • 状态改变过程

    1. SetPendingKill, Flags = 10010000,加入了PendingKill状态,此时有PendingKill和Native两种状态
    2. IsPendingKill, ret = 10010000 & 10000000 = 10000000 = true,判断是否有 PendingKill 状态
    3. ClearPendingKill, Flags = 10010000 & 0111111 = 00010000,清除了PendingKill状态,此时只有 NativeNative 状态
    4. 其他以此类推
  • 作用场景

    • 用于同一个标记Flag中需要保存多种状态,否者用普通的枚举1,2,3…就可以。