句柄的可移植位域

Portable bit fields for Handles

我想使用 "Handles" 数据并将其存储在对象缓冲区中以减少分配开销。句柄只是包含对象的数组的索引。但是我需要检测 use-after-reallocations,因为这很容易滑入。常见的方法似乎是使用位域。然而,这会导致 2 个问题:

  1. 位字段是实现定义的
  2. 位移位不可跨 big/little endian 机器移植。

我需要的:

我得到的:

template<class T_HandleDef, typename T_Storage = uint32_t>
struct Handle
{
    typedef T_HandleDef HandleDef;
    typedef T_Storage Storage;

    Handle(): handle_(0){}
private:
    const T_Storage handle_;
};

template<unsigned T_numIndexBits = 16, typename T_Tag = void>
struct HandleDef{
    static const unsigned numIndexBits = T_numIndexBits;
};

template<class T_Handle>
struct HandleAccessor{
    typedef typename T_Handle::Storage Storage;
    typedef typename T_Handle::HandleDef HandleDef;

    static const unsigned numIndexBits = HandleDef::numIndexBits;
    static const unsigned numMagicBits = sizeof(Storage) * 8 - numIndexBits;

    /// "Magic" struct that splits the handle into values
    union HandleData{
        struct
        {
            Storage index : numIndexBits;
            Storage magic : numMagicBits;
        };
        T_Handle handle;
    };
};

用法例如:

typedef Handle<HandleDef<24> > FooHandle;
FooHandle Create(unsigned idx, unsigned m){
    HandleAccessor<FooHandle>::HandleData data;
    data.idx = idx;
    data.magic = m;
    return data.handle;
}

我的目标是使句柄尽可能不透明,添加布尔检查,但仅此而已。句柄的用户除了传递它之外不能对它做任何事情。

所以问题我运行变成了:

注意:已经有关于位域和联合的问题。摘要:

注意:没有 C++11,但允许 boost。

答案非常简单(基于另一个问题,我忘记了 link 和@Jeremy Friesner 的评论):

因为 "numbers" 在 C++ 中已经是一种抽象,当变量在 CPU 寄存器中时(当它用于任何计算时,可以确保始终具有相同的位表示) C++ 中的位移位也是以与字节序无关的方式定义的。这意味着 x << 1 总是等于 x * 2(因此是大端) 只有在保存到文件时,send/recv 通过网络或从内存中以不同方式访问它(例如通过指针...)

这里不能使用 C++ 位域,因为不能 100% 确定 "entries" 的顺序。位域容器可能没问题,如果它们允许以 "number".

的形式访问数据

Savest(仍然)使用移位,在这种情况下非常简单(只有 2 个值)在 storing/serialization 期间,数字必须以字节序不可知的方式存储。