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

Using the address of a member variable as an ID

本文关键字:ID 地址 成员 变量      更新时间:2023-10-16

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

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

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

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

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

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

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

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

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

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

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