0

我试图避免声明枚举或使用字符串。尽管这样做的理由似乎令人怀疑,但完整的解释是无关紧要的。

我的问题很简单。我可以使用成员变量的地址作为唯一 ID 吗?

更具体地说,要求是:

  • ID 不必序列化。
  • ID 将是受保护的成员 - 仅由拥有对象在内部使用(即使在相同的类实例之间也不会比较 ID)。
  • 子类需要访问基类 ID,并且可以添加它们的新 ID。

所以第一个解决方案是这样的:

class SomeClass
{
    public:
        int mBlacks;

        void AddBlack( int aAge )
        {
            // Can &mBlacks be treated as a unique ID?
            // Will this always work?
            // Is void* the right type?
            void *iId = &mBlacks;

            // Do something with iId and aAge
            // Like push a struct of both to a vector.
        }
};

而第二种解决方案是这样的:

class SomeClass
{
    public:
        static int const *GetBlacksId()
        {
            static const int dummy = 0;
            return &dummy;
        }

        void AddBlack( int aAge )
        {
            // Do something with GetBlacksId and aAge
            // Like push a struct of both to a vector.
        }
};
4

1 回答 1

2

此对象的任何其他int数据成员,以及同一进程中mBlacks不同实例的成员,都与该实例SomeClass的成员具有相同的地址。因此,您可以安全地将其用作流程中的唯一 ID。mBlacksSomeClass

的空基类子对象SomeClass可以具有与 相同的地址mBlacks(如果SomeClass有任何空基类,则它没有),并且作为char的第一个字节的对象mBlacks具有与mBlacks. 除此之外,没有其他对象具有相同的地址。

void*将作为类型工作。int*也可以,但也许你想为不同的 id 使用不同类型的数据成员。

但是,此实例的 ID 是唯一的。同一类型的不同实例具有不同的 ID。您的一条评论表明这实际上不是您想要的。

如果您希望该类型的每个都具有唯一的 ID,并且对于具有相同值的所有对象都具有相同的 ID,那么您最好从对象的所有重要字段中组合 ID。或者只是比较对象的相等性而不是它们的 ID,使用合适的operator==and operator!=

或者,如果您希望 ID 唯一地标识一个值何时首次构造,而不是通过复制构造函数和复制赋值(以便作为相同“原始”副本的所有对象共享一个 ID),那么这样做的方法是在所有其他构造函数中分配一个新的唯一 ID,将其存储在数据成员中,并将其复制到复制构造函数和复制赋值运算符中。

获取新 ID 的规范方法是拥有一个 global[ *] 计数器,每次取值时都会递增该计数器。这可能需要使线程安全,具体取决于哪些程序使用该类(以及它们如何使用它)。然后,在给定的程序运行中,值将是唯一的,前提是计数器的类型足够大。

另一种方法是生成一个 128 位的随机数。这在理论上并不令人满意,但假设一个不错的随机源发生碰撞的机会并不比您的程序因某些不可避免的原因(如宇宙射线引起的数据损坏)而失败的机会大。当对象的来源广泛分布时(例如,如果您需要在不同进程或不同机器上唯一的 ID),随机 ID 比顺序 ID 更容易。如果您选择使用机器的 MAC 地址、随机数、时间、每个进程的全局 [ *] 计数器、PID 以及您想到并动手的任何其他内容(或标准 UUID)的组合,则可以)。但这对于您的需求可能有点过头了。

[ *] 不必严格地是全局的——它可以是类的私有静态数据成员,或者是函数的静态局部变量。

于 2012-12-07T02:43:43.073 回答