2010-01-01 93 views
27

¿Cuál puede ser el mejor algoritmo para generar una identificación única en C++? La ID de longitud debe ser un entero sin signo de 32 bits.Algoritmo para generar una ID única en C++?

+12

Único en qué sentido: en su máquina, en su aplicación? –

+1

Debe usar un GUID. – SLaks

+9

SLaks: ¿cómo se puede decir eso sin conocer sus requisitos? ¿Y desde cuándo es un GUID de 32 bits? –

Respuesta

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

Lo sentimos, en teoría, si dos máquinas hacen esto al mismo tiempo, ambas máquinas obtendrán el mismo uid, por lo que el número no es único en todas las computadoras. Ver el comentario de Neil a la pregunta principal. Es correcto si la demanda es solo para obtener unicidad en la misma máquina a lo largo del tiempo, y no exclusividad en todas las máquinas. – elcuco

+5

Además, GetTickCount() no es muy preciso. Podría llamarlo tres veces seguidas y obtener la misma respuesta. –

52

Obtener una ID de 32 bits es intuitivamente simple: la siguiente. Funciona 4 mil millones de veces. Único durante 136 años si necesita uno por segundo. El diablo está en los detalles: ¿cuál fue el anterior? Necesita una forma confiable de conservar el último valor utilizado y una forma atómica para actualizarlo.

Lo difícil que será depende del alcance de la ID. Si es un hilo en un proceso, entonces solo necesita un archivo. Si se trata de varios hilos en un proceso, entonces necesitas un archivo y un mutex. Si hay múltiples procesos en una máquina, entonces necesitas un archivo y un mutex con nombre. Si se trata de múltiples procesos en varias máquinas, entonces debe asignar un proveedor de ID autoritativo, un único servidor con el que todas las máquinas hablen. Un motor de base de datos es un proveedor común como ese, tienen esta función incorporada como una columna de incremento automático.

El costo de obtener la ID aumenta progresivamente a medida que se amplía el alcance. Cuando resulta poco práctico, el alcance es Internet o el proveedor es demasiado lento o no está disponible, entonces debe renunciar a un valor de 32 bits. Cambia a un valor aleatorio. Uno que sea lo suficientemente aleatorio como para que la probabilidad de que la máquina sea golpeada por un meteoro sea al menos un millón de veces más probable que repetir la misma identificación. Una buena identificación. Es solo 4 veces más grande.

+0

¿Una buena respuesta para la vista general del problema, cualquier sugerencia sobre un método estándar para la última solución, con el número aleatorio? ¿Cuál es un buen enfoque práctico para generar números aleatorios suficientemente buenos? – overlii

+0

¿Quizás te refieres a "UUID", como se describe en este artículo de la wikipedia? http://en.wikipedia.org/wiki/Universally_unique_identifier#Random_UUID_probability_of_duplicates – overlii

+0

Sí. Si un número es globalmente único (guid) o universalmente único (uuid) es algo que no quiero tocar con un polo de diez metros. Es un gran universo por ahí :) –

0

Hay poco sentido, pero si usted está buscando un ID único para los objetos dentro de su aplicación siempre se puede utilizar un enfoque Singleton similar a

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; 
} 

Y ahora se puede obtener un identificador único en cualquier momento haciendo:

IDGenerator::instance()->next()

+2

static IDGenerator & instance() { static IDGenerator Generator; return Generator; } – ROAR

+0

La respuesta original permite la destrucción del singleton. La var estática local es más rápida de implementar pero pierdes esa opción. –

9

Aquí está el ID más simple que puedo pensar.

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

En cualquier momento, este ID será único en toda la aplicación. Ningún otro objeto estará ubicado en la misma dirección. Por supuesto, si reinicia la aplicación, al objeto se le puede asignar una nueva ID. Y una vez que finaliza el tiempo de vida del objeto, a otro se le puede asignar el mismo ID.

Y a los objetos en diferentes espacios de memoria (por ejemplo, en diferentes computadoras) se les pueden asignar identificadores idénticos.

Y por último pero no menos importante, si el tamaño del puntero es mayor que 32 bits, la asignación no será única.

Pero dado que no sabemos nada sobre qué tipo de identificación desea y qué tan única debe ser, esta parece ser una buena respuesta.

+0

Mala idea. Imagine una aplicación de 64 bits. Existe una gran posibilidad de que 32 bits de esa dirección sean 0x00000000, o al menos los mismos para todas las direcciones de objeto en un programa. (Nota: es probable que truncar los resultados de reinterpret_cast dependan de endianness) – MSalters

+7

Ya lo señalé. Si el tamaño del puntero es mayor que 32 bits, obtendrá colisiones. Pero dado que no sabemos prácticamente nada sobre para qué se necesita la identificación, ni en qué tipo de aplicación, solo quería sugerir la solución simple y obvia. – jalf

+1

¿Hay alguna forma de que esto funcione con 64 bits y 32 bits? –

0

Si puede permitirse usar Boost, entonces hay una biblioteca UUID que debería funcionar. Es muy fácil de usar: consulte la documentación y this answer.

Cuestiones relacionadas