最佳实践:如何获取对象的唯一标识符

17

我有几个对象,需要为它们生成一个唯一标识符,在每个对象的生命周期内不会更改/重复。

基本上我想要获得/生成我的对象的唯一标识符,类似于这样

int id = reinterpret_cast<int>(&obj);
int id = (int)&obj;

我明白上面的代码是个坏主意,因为 int 可能不够大来存储地址等信息。

那么,获取对象的唯一标识符的最佳实践是什么,这将是一个可移植的解决方案?


你可以使用“size_t”,它应该与指针类型一样大。例如,如果你只需要检查是否相同/不同,为什么不直接存储指针本身呢? - David Rodríguez - dribeas
5
如果您的ID不需要在程序运行或地址空间边界之间持久存在,那么地址就可以胜任。uintptr_t是足够大的整数类型。 - jthill
6个回答

18

根据您对“唯一性”的要求,有几种选择:

  • 如果您可以接受在一个地址空间(“在一个程序执行中”)内唯一,并且您的对象保持在内存中,那么指针是可以的。但是有陷阱:如果您的对象位于容器中,则每次重新分配都可能更改您的对象的标识,并且如果允许复制对象,则从某些函数返回的对象可能已在相同的地址处创建。
  • 如果您需要更全局的唯一性,例如因为您正在处理通信程序或持久数据,请使用GUIDs / UUIds,例如boost.uuid
  • 您可以从某些静态计数器创建唯一的整数,但要注意以下陷阱:
    • 确保您的增量是原子的
    • 防止复制或创建自定义的复制构造函数、赋值语句。

就我个人而言,每当我负担得起时,我的选择总是UUID,因为它们为我提供了一些放心,不必考虑所有的陷阱。


2
如果以“变量”和“值”的术语来思考,那么第一个要点实际上是这样说的:如果您需要变量的唯一标识符,以便没有两个变量具有相同的ID,则可以使用它们的地址;如果您需要为值提供唯一标识符,以便没有两个变量包含具有相同ID的值,则使用变量的地址将无法起作用。 - Joker_vD

12
如果对象需要唯一标识,您可以在构造函数中生成唯一ID:
struct Obj
{ 
   int _id;
   Obj() { static int id = 0; _id = id++; }
};

你需要决定如何处理副本/分配(相同id - 上述方法可行 / 不同id的话 - 你需要一个复制构造函数和可能是静态类成员而不是静态局部变量)。


5
如果应用程序是多线程的,那么这需要进行同步,例如在Windows中使用InterlockedIncrement。 - Steve Townsend
1
如果int是32位的,并且您打算无限运行此过程,则应准备处理负ID(或将其设置为无符号),并处理回绕到零(因此在创建新对象/ ID时必须检查ID的唯一性)。另外,为了保险起见,我会将零作为无效句柄。 - mark

5
当我调查这个问题时,我很快就找到了Boost UUID库(通用唯一标识符,http://www.boost.org/doc/libs/1_52_0/libs/uuid/)。然而,随着我的项目不断发展,我转向了Qt的GUID库(全局唯一标识符,https://doc.qt.io/qt-5/quuid.html)。
对我来说,学到的一课是要开始声明自己的UUID类并隐藏实现,以便以后可以切换到你认为合适的任何类。
希望这能有所帮助。

0
如果您的对象是一个类,那么您可以拥有一个静态成员变量,将其初始化为0。然后在构造函数中,您将此值存储到类实例中并递增静态变量:

class

Indexed
{
public:
   Indexed() :
       m_myIndex( m_nextIndex++ )
   { }

   int getIndex() const
   { return m_myIndex; }

private:
   const int m_myIndex;
   static int m_nextIndex;
};

0

使用对象地址作为唯一标识符似乎不是一个坏主意。为什么要将其强制转换为整数?只需使用==比较指针即可:

MyObject *obj1, *obj2;
...
if (obj1 == obj2) ...

当然,如果您需要将 ID 写入数据库或类似情况,则此方法无效。指针的相同值在多次运行之间是可能的。另外,请不要重载比较操作符(==)。


obj1 == obj2 是未定义行为。 - Luchian Grigore
@LuchianGrigore 我不明白这会导致未定义的行为。您能否详细说明一下(并提供圣标准的参考)? - Agentlien
这只是一个代码片段,不是一个完整的程序。我现在添加了“...”以明确需要更多的代码行。 - Audrius Meškauskas
@LuchianGrigore 好吧,但是... 我至少认为他指的是在声明和检查之间加上// 在此处执行更多操作... - Agentlien
1
@LuchianGrigore 这导致他更新了他的帖子,所以我想这是一件好事。 :) 不过在将来,如果您添加了有关开始出了什么问题的解释,那可能会更有帮助。 ;) - Agentlien

0
如果您需要在分布式环境中使用唯一标识符,请使用boost::uuid

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接