как лучше всего использовать тип C uuid_t в качестве ключа в std::map?

Является ли это подходящим способом предоставления уникальных ключей на карте? Другими словами, создается ли ключ из уникального значения, содержащегося в uuid, или из указателя на структуру uuid_t? Побочный вопрос, есть ли более эффективный контейнер, когда мне не нужен порядок по ключам внутри контейнера?

#include <uuid/uuid.h>

int main(int argc, char **argv)
{    
   std::map<uuid_t,int> myMap;         

   uuid_t id1;
   uuid_t id2;

   uuid_generate( (unsigned char *)&id1 );  
   uuid_generate( (unsigned char *)&id2 );

   myMap[id1] = 5;
   myMap[id2] = 4;

}

person Dave    schedule 20.11.2011    source источник
comment
Зачем тогда тебе ключи? Дайте нам больше фона. Почему не vector или просто array. Есть много видов контейнеров. Есть ли причина, по которой вам нужен уникальный идентификатор?   -  person Kiril Kirov    schedule 20.11.2011
comment
Это очень хороший вопрос, Кирилл, и он заставил меня задуматься над этой проблемой. Я создаю приложение, которому потенциально может потребоваться агрегировать данные, созданные разными, отключенными пользователями, запускающими разные экземпляры приложения - без общей базы данных для общения. Таким образом, ключ с автоматически увеличивающимся целым числом не будет работать — идея состоит в том, чтобы не генерировать никаких конфликтов ключей во всех входящих источниках данных. Я полагаю, что некоторая комбинация из machine_id, временной метки и пользователя тоже сработает, но я действительно не понимаю, как бы я использовал хеширование для создания уникального ключа.   -  person Dave    schedule 20.11.2011
comment
Я ищу высокопроизводительный индекс, поэтому стараюсь избегать использования строк из-за того, что, как я предполагаю, будет МНОГО сравнений строк. Это помогает?   -  person Dave    schedule 20.11.2011
comment
Я не уверен, что понял все это. Вы имеете в виду, что эти пользователи будут как-то идентифицированы и что один и тот же пользователь может подключаться несколько раз и вам нужно хранить все данные о пользователе в одном месте?   -  person Kiril Kirov    schedule 20.11.2011
comment
Не совсем, но близко. Разные пользователи будут генерировать данные потенциально одновременно, без связи друг с другом. Позже мне нужно объединить записи и, чтобы упростить связь между ними, каким-то образом иметь возможность указывать одну запись на другую. Думаю, ссылка будет состоять из описания и уникального идентификатора (каким бы он ни оказался) целевой записи. Это часть коллективного приложения управления знаниями.   -  person Dave    schedule 20.11.2011
comment
Гипотетический индекс, который я псевдокодировал выше, используется для быстрого доступа к связанным записям, чтобы реализация поиска могла быстро сканировать записи, которые были связаны друг с другом. На самом деле, int, хранящийся как значения на карте, является просто упрощением, чтобы сфокусировать вопрос, я на самом деле храню указатели на кешированные записи... Я просто не думал, что эта часть имеет значение! :)   -  person Dave    schedule 20.11.2011
comment
А, теперь я вижу. Извините, тут я ничем помочь не могу. Удачи в любом случае :)   -  person Kiril Kirov    schedule 20.11.2011
comment
void uuid_copy( uuid_t dst , uuid_t src); должно привлечь ваше внимание здесь так же, как и void uuid_generate( uuid_t out );. У них должен возникнуть вопрос: как эти функции заполняют dst и out, если нет ни ptr, ни reference модификации uuid_t?   -  person ony    schedule 20.11.2011
comment
Кстати, вы можете посмотреть на std::hash_map   -  person ony    schedule 20.11.2011
comment
@ony Потому что uuid_t в libuuid определяется как тип массива, а типы массивов в объявлениях параметров незаметно преобразуются в типы указателей.   -  person rodrigo    schedule 21.11.2011
comment
@rodrigo, это именно то, на что я указывал;) на самом деле они не конвертируются (просто поместите uuid_t внутрь struct, и все изменится), но когда uuid_t передается напрямую (как возвращаемое значение или аргумент), он обрабатывается как указатель   -  person ony    schedule 22.11.2011
comment
@ony, вы подняли хороший вопрос, который я не включил в свой вопрос ... порядок НЕ имеет значения в моей реализации. Вероятно, мне следует взглянуть на std::hash_map и std::unordered_map вместо std::map и посмотреть, какой из них более подходит (в настоящее время я недостаточно хорошо их знаю, чтобы различать).   -  person Dave    schedule 09.03.2015
comment
@ Дэйв, насколько я знаю, между std::hash_map и std::unordered_map не должно быть разницы. Последний из С++ 11, другой до С++ 11. Единственная разница заключается в функциях С++ 11 (перемещение, размещение и т. д.).   -  person ony    schedule 09.03.2015


Ответы (3)


Я предполагаю, что лучший способ использовать сторонние C-структуры — это использовать их через их дружественные функции. Итак, если вы хотите использовать uuid_t в STL, я бы предложил вам создать какой-то интерфейс/оболочку C++ для этой структуры, например

struct Uuid {
  uuid_t uuid;
  Uuid(const Uuid &other) { uuid_copy(uuid, other.uuid); }
  Uuid(const uuid_t other_uuid) { uuid_copy(uuid, other_uuid); }
  void generateInplace() { uuid_generate(uuid); }
  static Uuid generate() { Uuid wrapped; uuid_generate(wrapped.uuid); return wrapped; }
  bool operator<(const Uuid &other) { return uuid_compare(uuid, other.uuid) < 0; }
  bool operator==(const Uuid &other) { return uuid_compare(uuid, other.uuid) == 0; }
  // ...
};

Это должно скрыть от вас тот факт, что uuid_t является не структурой, а указателем на массив (т.е. typedef unsigned char uuid_t[16]).

Примечание: существует ускоренная версия библиотеки uuid.

person ony    schedule 20.11.2011
comment
Это не отвечает на то, как вы генерируете уникальное хеш-значение из uuid_t. - person Mark Ingram; 13.11.2013
comment
@MarkIngram, std::map не использует хэш-значения. Он использует только оператор сравнения. Если вам нужно использовать этот класс в std::unordered_map (хеш-таблица), вам нужно определить либо std::hash<uuid_t>, и std::equal_to<uuid_t>, либо переопределить соответствующие параметры шаблона. Но это будет другой вопрос и другой ответ. - person ony; 13.11.2013
comment
Извините, я сам искал unordered_map и не заметил, что OP указал только карту. - person Mark Ingram; 13.11.2013
comment
@ony, спасибо за дополнительную информацию о std::hash, это вполне может быть идеальным решением! - person Dave; 09.03.2015

Контейнеры STL всегда содержат копии объекта, и это также относится к ключам карты.

Самый простой способ поддержать это — использовать собственный компаратор для карты.

struct UUIDComparator
{
    bool operator()(const uuid_t &a, const uuid_t &b)
    {
        //compare and return a < b
    }
};
std::map<uuid_t, int, UUIDComparator> map;

Другим слегка спорным решением было бы преобразовать uuid_t в std::pair<uint64_t, uint64_t>, поскольку оба типа имеют ширину 128 бит и, AFAICT, совместимы с макетом. И std::pair можно напрямую использовать в качестве ключей карты.

std::map<std::pair<uint64_t, uint64_t>, int, UUIDComparator> map;
person rodrigo    schedule 20.11.2011
comment
Как я упоминал ранее, uuid_t на самом деле является типом unsigned char[16]. Не означает ли это, что std::map<uuid_t, int, UUIDComparator>::key_type будет иметь тип usigned char* и все операции типа operator[](...) будут работать со ссылками на указатели? - person ony; 20.11.2011
comment
О, я думал, вы сказали uuid_t struct. Если это тип массива, он не будет работать, потому что типы массивов не копируются. И нет, он не распадется на указатель, то есть на выражения, а не на typedefs. Но если это структура, даже с массивом внутри, она будет работать нормально. - person rodrigo; 20.11.2011
comment
Это не мой вопрос, но поскольку есть #include <uuid/uuid.h>, я предполагаю, что uuid_t это typedef из библиотеки libuuid. В моей системе эта библиотека определяет этот тип как массив. Насчет распада на указатель - вы правы, но конструктор std::pair<uuid_t, int> не примет uuid_t в качестве первого аргумента, я думаю. - person ony; 21.11.2011

Проще: uuid_unparse(...) преобразует его в char* (длиной 37 символов), который затем можно обернуть строкой...

person Don Doerner    schedule 30.01.2013