Меня немного смущает семантика кучи и сравнения по значению и по ссылке, связанная с помещением ключа std::string
и большого значения struct
в такой контейнер, как boost::interprocess::map
.
Вот моя ситуация и некоторые определения типов, которые я использую:
typedef std::string AreaKeyType;
typedef DATA_AREA_DESC AreaMappedType; // DATA_AREA_DESC is a big struct.
typedef std::pair<const AreaKeyType, AreaMappedType> AreaValueType;
typedef boost::interprocess::allocator<AreaValueType, boost::interprocess::managed_shared_memory::segment_manager> AreaShmemAllocator;
typedef boost::interprocess::map<AreaKeyType, AreaMappedType, std::less<AreaKeyType>, AreaShmemAllocator> AreaMap;
Вот как я вставляю AreaValueType (это typedef для std::pair):
AreaValueType A(areaKey, arearec);
anAreaMap->insert(A);
Я полагаю, что приведенный выше код копирует A, который является парой std::pair в моем локальном стеке (не разделяемой памяти) в область разделяемой памяти. Могу ли я получить дескриптор этой общей области памяти внутри boost::interprocess::map или я ограничен извлечением этой записи целиком и сохранением ее целиком? (Другими словами, могу ли я сохранить что-то вроде структуры в межпроцессной карте boost, а затем обновить один байт внутри этой записи, или мне нужно только обновить всю запись, заменив все байты в структуре DATA_AREA_DESC совершенно новыми байт.)
Некоторые дополнительные уточнения:
У меня есть простой старый API экспорта ANSI C DLL, который внутренне использует C++ и Boost::interprocess::map. Ожидается, что функция создаст элемент на карте, а затем вернет дескриптор. Как я могу вставить что-то в boost::interprocess::map, а затем вернуть дескриптор этой сущности для пользователей, не использующих C++, желательно привести к
void*
илиunsigned long
? Все, что я могу сделать, это получить данные из общей памяти, просматривая значение ключа std::string, и записать новую запись в память. Вместо этого я хотел бы иметь возможность сохранить ссылку на объект общей памяти.Если я не могу сделать это напрямую, как я могу сделать это косвенно? Я полагаю, что мог бы сохранить неразделяемую память std::vector и выделить неразделяемую память std::string, содержащую значение areaKey, которая является std::string, а затем выполнить приведение
void*
элемент обратно вstd::string
, а затем использовать его для извлечения записи из области общей памяти. Все это кажется большим количеством работы, чем должно быть строго необходимо для чего-то столь элементарного. Возможно, boost::interprocess::map не подходит для моих требований?
Что я пробовал? Это компилируется, но я понятия не имею, правильно ли я это делаю. Почему-то я чувствую себя некрасиво, разыменовывая ::iterator
, возвращенный из find
, а затем сразу же получая его адрес, например:
void ** handle; // actually a parameter in my api.
*handle = (void*)&(*anAreaMap->find(areaKey));
Обновить Все вышеперечисленное работает. Однако очень разумный совет в ответе ниже НЕ работает. Использование boost::interprocess::string приводит к полному сбою и сбоям во время выполнения. Использование std::string, которое не имеет права работать, если только авторы Boost специально не закодировали поддержку std::string, на самом деле прекрасно работает.