2010-01-01 7 views
27

Что может быть лучшим алгоритмом для создания уникального идентификатора на C++? Идентификатор длины должен быть 32-разрядным целым без знака.Алгоритм для создания уникального идентификатора в C++?

+12

Уникальный в каком смысле - на вашей машине, в вашем приложении? – 2010-01-01 14:07:21

+1

Вы должны использовать GUID. – SLaks

+9

SLaks - как вы можете сказать это, не зная его требований? А с каких это GUID 32 бит? – 2010-01-01 14:10:51

ответ

7

Вы можете увидеть this. (Полный ответ, я думаю, находится на переполнении стека.)
Некоторая заметка для уникального идентификатора в C++ в Linux в this site. И вы можете использовать uuid в Linux, см. Этого человека page and sample для этого.

Если вы используете окна и вам нужны API окон, см. Это MSDN page.

Эта страница Википедии также полезна: http://en.wikipedia.org/wiki/Universally_Unique_Identifier.

+2

да, хотел бы использовать linux. Спасибо за ссылки. – Ajay

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

Извините, теоретически, если две машины делают это одновременно - обе машины получат одинаковый uid, поэтому число не уникально на всех компьютерах. См. Комментарий Нила к основному вопросу. Это правильно, если требование состоит только в том, чтобы получить уникальность на одной машине во времени, а не на уникальность между машинами. – elcuco

+5

Plus GetTickCount() не очень точен. Вы можете назвать это три раза подряд и получить тот же ответ. –

52

Получение уникального 32-битного идентификатора интуитивно просто: следующее. Работает 4 миллиарда раз. Уникальный за 136 лет, если вам нужна одна секунда. Дьявол в деталях: что было предыдущим? Вам нужен надежный способ сохранить последнее использованное значение и атомный способ его обновления.

Как сильно это будет зависеть от объема идентификатора. Если это один поток в одном процессе, вам нужен только файл. Если это несколько потоков в одном процессе, вам нужен файл и мьютекс. Если это несколько процессов на одной машине, вам нужен файл и именованный мьютекс. Если это несколько процессов на нескольких компьютерах, вам необходимо назначить авторитетного поставщика идентификаторов, одного сервера, с которым разговаривают все компьютеры. Механизм базы данных - это обычный провайдер, у которого есть встроенная функция как функция, столбец с автоматическим увеличением.

Затраты на получение ИД прогрессивно увеличиваются по мере расширения сферы действия. Когда это становится нецелесообразным, объем Интернета или провайдера слишком медленный или недоступный, тогда вам нужно отказаться от 32-битного значения. Переключитесь на случайное значение. Тот, который достаточно случайен, чтобы вероятность того, что машина поражена метеор, по крайней мере в миллион раз более вероятна, чем повторение того же идентификатора. Goo-ID. Это всего в 4 раза больше.

+0

Хороший ответ для обзора проблемы, любые указатели на стандартный метод для последнего решения со случайным числом? Какой хороший практический подход для создания достаточно хороших случайных чисел? – overlii

+0

Возможно, вы имели в виду «UUID», как описано в этой статье в Википедии? http://en.wikipedia.org/wiki/Universally_unique_identifier#Random_UUID_probability_of_duplicates – overlii

+0

Да. Независимо от того, является ли число глобально уникальным (guid) или универсально уникальным (uuid), я не хочу касаться десятифутового полюса. Это большая вселенная :) –

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

И теперь вы можете получить уникальный идентификатор в любое время делая:

IDGenerator::instance()->next()

+2

static IDGenerator & instance() { статический генератор IDGenerator; return Генератор; } – ROAR

+0

Оригинальный ответ позволяет уничтожить синглтон. Локальный статический var быстрее реализуется, но вы теряете эту опцию. –

9

Вот простейший ID я могу думать.

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

В любой момент времени этот идентификатор будет уникальным в приложении. Ни один другой объект не будет находиться по тому же адресу. Конечно, если вы перезапустите приложение, ему может быть назначен новый идентификатор. И как только срок жизни объекта заканчивается, другому объекту может быть присвоен один и тот же идентификатор.

И объектам в разных пространствах памяти (скажем, на разных компьютерах) могут быть присвоены идентичные идентификаторы.

И последнее, но не менее важное, если размер указателя больше 32 бит, сопоставление не будет уникальным.

Но поскольку мы ничего не знаем о том, какой идентификатор вам нужен, и насколько он уникален, это кажется хорошим ответом, как любой.

+0

Плохая идея. Представьте себе 64-битное приложение. Существует очень большая вероятность того, что 32 бита этого адреса будут 0x00000000 или, по крайней мере, одинаковы для всех адресов объектов в программе. (Примечание: обрезание результатов reinterpret_cast, вероятно, будет зависеть от сущности) – MSalters

+7

Я уже указал это. Если размер указателя больше 32 бит, вы получите столкновение. Но поскольку мы практически ничего не знаем о том, для чего нужен идентификатор или в каком типе приложений, я просто хотел предложить простое и очевидное решение. – jalf

+1

Есть ли способ для этого, чтобы это работало для 64 бит и 32 бит? –

0

Если вы можете позволить себе использовать Boost, то есть библиотека UUID, которая должна делать трюк. Это очень просто использовать - проверьте документацию и this answer.

Смежные вопросы