在C++中生成唯一ID的算法?

37

在C++中生成唯一ID的最佳算法是什么? ID长度应为32位无符号整数。


14
在哪方面是独特的 - 在你的计算机上还是在你的应用程序中? - anon
12
你怎么能在不了解他的需求的情况下这样说呢?而且自从什么时候GUID变成了32位了呢? - anon
说实话,它们两者之间有什么区别? - Ajay
4
@Ajay: 关于区别 - 如果这在你的应用程序中,那么一个简单的计数器就可以完成任务。如果这是在机器上,那么你需要确保它在运行同一程序的不同进程之间是唯一的,这更加困难。 - Eli Bendersky
GUID是Windows特定的API,不是跨平台的... - Denise Skidmore
显示剩余2条评论
6个回答

69

获取一个独特的32位ID很直观简单:下一个。可以工作40亿次。如果每秒需要一个,则136年内唯一。关键在于细节:上一个是什么?您需要一种可靠的方式来保存上次使用的值,并以原子方式更新它。

难度取决于ID的范围。如果只是一个进程中的一个线程,则只需要一个文件。如果是一个进程中的多个线程,则需要一个文件和互斥锁。如果是一个机器上的多个进程,则需要一个文件和命名互斥锁。如果是多个机器上的多个进程,则需要分配一个权威的ID提供者,一个所有机器都与之通信的单个服务器。数据库引擎常常充当这样的提供者,他们将其内置为特性,称为自动递增列。

随着范围的扩大,获取ID的成本逐渐增加。当范围变得不切实际时,如Internet或提供者速度太慢或不可用,则需要放弃32位值。转而使用随机值。足够随机,使得机器被流星击中的可能性至少比重复相同ID的可能性高一百万倍。一个好的ID。大小只是它的四倍。


对于问题概述的回答很好,有没有关于最后一个解决方案(包含随机数)的标准方法的指针?生成足够好的随机数的好的实用方法是什么? - overlii
也许你指的是由这篇维基百科文章描述的“UUID”?http://en.wikipedia.org/wiki/Universally_unique_identifier#Random_UUID_probability_of_duplicates - overlii
是的。一个数字是全局唯一标识符(GUID)还是通用唯一标识符(UUID),这是我不想碰的东西。宇宙是如此之大 :) - Hans Passant

14

这是我能想到的最简单的ID。

MyObject obj;
uint32_t id = reinterpret_cast<uint32_t>(&obj);

在任何时候,此ID将在整个应用程序中是唯一的。没有其他对象会位于相同的地址。当然,如果重新启动应用程序,则可能会为对象分配新的ID。当对象的生命周期结束后,可能会分配相同的ID给另一个对象。

不同内存空间中(例如,在不同计算机上)的对象可能会被分配相同的ID。

最后但并非最不重要的是,如果指针大小大于32位,则映射将不是唯一的。

但由于我们不知道您想要什么类型的ID以及它应该有多独特,因此这似乎是一个与其他任何答案一样好的答案。


1
不太好的想法。想象一下一个64位应用程序。很有可能这个地址的32位将是0x00000000,或者至少对于程序中所有对象的地址来说都是相同的。(注意:截断reinterpret_cast结果很可能取决于字节序) - MSalters
8
我已经指出过了。如果指针大小大于32位,就会发生冲突。但是由于我们几乎不知道所需ID的用途或应用类型,我只是想建议一个简单明显的解决方案。 - jalf
1
有没有办法让它适用于64位和32位? - dev_nut
6
使用这个方法时要小心。我曾经使用同样的方法,当你移除对象并创建新对象时,新对象可能会具有相同的地址。如果你的应用程序使用多线程,这将非常危险。 - Unick

8

1
DWORD uid = ::GetTickCount();
::Sleep(100);

1
抱歉,在理论上,如果两台机器同时执行此操作,则两台机器将获得相同的UID,因此该数字在计算机之间不是唯一的。请参见Neil对主要问题的评论。如果要求仅在同一台机器上跨时间获取唯一性而不是在多台机器之间获取唯一性,则是正确的。 - elcuco
6
GetTickCount()函数并不是非常精确。你可能会连续调用三次,但得到的响应却是相同的。 - John Dibling

1
如果您可以使用Boost,那么UUID库应该能解决问题。它非常易于使用-请查阅文档和this answer

0

虽然上下文很少,但如果您正在寻找应用程序内对象的唯一标识符,则可以始终使用类似于单例的方法。

class IDGenerator {
   public:
      static IDGenerator * instance ();
      uint32_t next () { return _id++; }
   private:
      IDGenerator () : _id(0) {}

      static IDGenerator * only_copy;
      uint32_t _id;
}

IDGenerator *
IDGenerator::instance () {
   if (!only_copy) {
      only_copy = new IDGenerator();
   }
   return only_copy;
}

现在您可以随时通过执行以下操作获取唯一的ID:

IDGenerator::instance()->next ()


3
静态ID生成器&实例() { 静态ID生成器生成器; 返回生成器; } - ROAR
原始答案允许销毁单例。局部静态变量实现更快,但您会失去该选项。 - Cross_

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