使用成员变量的地址作为ID

时间:2012-12-07 02:30:42

标签: c++

我试图避免声明枚举或使用字符串。虽然这样做的理由可能看起来很可疑,但完整的解释是无关紧要的。

我的问题很简单。我可以将成员变量的地址用作唯一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.
        }
};

1 个答案:

答案 0 :(得分:2)

此对象中没有其他int数据成员,并且同一进程中mBlacks的其他SomeClass个实例的mBlacks成员与SomeClass具有相同的地址此SomeClass实例的成员。因此,您可以安全地将其用作流程中的唯一ID。

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

void*将作为类型使用。 int*也可以使用,但是您可能希望将不同类型的数据成员用于不同的ID。

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

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

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

获取新ID的规范方法是使用全局[*]计数器,每次获取值时都会递增。这可能需要根据程序使用类(以及它们如何使用它)来进行线程安全。如果计数器的类型足够大,那么值在程序的给定运行中将是唯一的。

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

[*]不一定是全局的 - 它可以是类的私有静态数据成员,也可以是函数的静态局部变量。