我試圖從幾天內解決這個問題。
在這個程式中有一個unordered_map從字串鍵到結構值的哪個。這個想法有效,但是當我把它unordered_map放在一個類中然后更容易訪問它時,我得到一個錯誤:
Eliminare.exe!std::_Hash<std::_Umap_traits<std::string,Data,std::_Uhash_compare<std::string,std::hash<std::string>,std::equal_to<std::string>>,boost::interprocess::allocator<std::pair<std::string,Data>,boost::interprocess::segment_manager<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,__int64,unsigned __int64,0>,0>,boost::interprocess::iset_index>>,0>>::_Find_last<std::string>(const std::string & _Keyval, const unsigned __int64 _Hashval) Row 1510 C
Eliminare.exe!std::unordered_map<std::string,Data,std::hash<std::string>,std::equal_to<std::string>,boost::interprocess::allocator<std::pair<std::string,Data>,boost::interprocess::segment_manager<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,__int64,unsigned __int64,0>,0>,boost::interprocess::iset_index>>>::at(const std::string & _Keyval) Riga 387 C
Eliminare.exe!MapCreator::getValue(std::string Key) Row 37 C
Eliminare.exe!main() Row 7 C
這是主要的:
#include "MapCreator.h"
int main() {
MapCreator mappaClass;
auto values = mappaClass.getValue("value");
}
雖然這是在 MapCreator.h 中:
#pragma once
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <unordered_map>
#include<iostream>
typedef struct Data
{
int a;
int b;
}dataClass;
namespace bost = boost::interprocess;
typedef std::string KeyType;
typedef dataClass MappedType;
typedef std::pair<std::string, dataClass> ValueType;
typedef bost::allocator<ValueType, bost::managed_shared_memory::segment_manager> ShmemAllocator;
typedef std::unordered_map<KeyType, MappedType, std::hash<KeyType>, std::equal_to<KeyType>, ShmemAllocator> MySHMMap;
class MapCreator
{
public:
MySHMMap* mappa = nullptr;
MapCreator() {
bost::shared_memory_object::remove(nameMemory);
bost::managed_shared_memory segment(bost::create_only, nameMemory, sizeDeclared);
ShmemAllocator alloc_inst(segment.get_segment_manager());
mappa = segment.construct<MySHMMap>("MySHMMapName")(alloc_inst);
dataClass value;
value.a = 12;
value.b = 1111;
mappa->insert(std::pair<std::string, dataClass>("value", value));
std::cout << mappa->at("value").a;
}
dataClass getValue(std::string Key) {
return mappa->at(Key);
}
private:
const int sizeDeclared = 65536;
const char nameMemory[20] = "SharedMemoryName";
};
建構式中的“ cout”MapCreator正確列印“12”,但使用該getValue函式,它會列印上述錯誤。
感謝您的幫助,如果您對代碼有任何疑問,請提出。
資訊:
- 編譯器:帶有 Visual Studio 2022 的 Visual C
- 沒有類的代碼運行良好
- boost類的版本是:1.78.0
uj5u.com熱心網友回復:
有多個問題。
第一個是segment建構式中的區域變數,這意味著mappa建構式回傳后是一個懸空指標。
其次,更大的問題是您的地圖正確使用了共享記憶體分配器,但字串沒有。字串也是動態分配的,因此除非您使字串也使用共享記憶體,否則您的解決方案將無法作業。
開始修復:
namespace bip = boost::interprocess;
namespace bc = boost::container;
using Segment = bip::managed_shared_memory;
using Mgr = Segment::segment_manager;
template <typename T> using Alloc = bip::allocator<T, Mgr>;
using MyString = bc::basic_string<char, std::char_traits<char>, Alloc<char>>;
using KeyType = MyString;
using MappedType = dataClass;
using ValueType = std::pair<KeyType const, MappedType>;
using MySHMMap = std::unordered_map<KeyType, MappedType, std::hash<MyString>,
std::equal_to<MyString>, Alloc<ValueType>>;
請注意,在我的編譯器上,它也需要
KeyType const在ValueType.
在執行中有額外的復雜性:segment必須是一個欄位,但它只能從初始化串列(或使用NSMI)構造。這意味著我們必須使remove初始化串列中也發生(在此之前)。這是我的初步嘗試:
template <typename T> using Alloc = bip::allocator<T, Mgr>;
using MyString = bc::basic_string<char, std::char_traits<char>, Alloc<char>>;
using KeyType = MyString;
using MappedType = dataClass;
using ValueType = std::pair<KeyType const, MappedType>;
using MySHMMap = boost::unordered_map<KeyType, MappedType, boost::hash<MyString>,
std::equal_to<MyString>, Alloc<ValueType>>;
class MapCreator {
public:
MapCreator()
: mappa(segment.find_or_construct<MySHMMap>("MySHMMapName")(
segment.get_segment_manager()))
{
mappa->emplace(MyString("value", segment.get_segment_manager()),
dataClass{12, 1111});
}
dataClass getValue(std::string key) const {
return mappa->at(MyString(key.c_str(), segment.get_segment_manager()));
}
private:
static constexpr int sizeDeclared = 65536;
// note: declaration order defines initialization order!
std::string_view nameMemory = "SharedMemoryName";
struct pre_remover {
pre_remover(const char* name)
{
bip::shared_memory_object::remove(name);
}
} pre_remove{nameMemory.data()};
Segment segment{bip::create_only, nameMemory.data(), sizeDeclared};
MySHMMap* mappa = nullptr;
};
筆記
- 也根本沒有理由為名稱分配 20 個字符的固定大小的緩沖區。
- 宣告成員的順序就是初始化它們的順序。這很重要,因為
mappa需要緊隨其后segment,例如
I found out that std::hash isn't actually specialized for the MyString instance, and because I know down the line I'd want to change that anyways I'm not wasting time to create a Hash function object. Instead, I'm switching to boost::unordered_map just so boost::hash<> is used
This is already working Live On Coliru
Prints:
12, 1111
Improvements
Scoped Allocators
Things are pretty clunky around the allocator/get_segment_manager(). Using scoped-allocators you can alleviate that:
template <typename T> using Alloc = bc::scoped_allocator_adaptor<bip::allocator<T, Mgr>>; using MyString = bc::basic_string<char, std::char_traits<char>, Alloc<char>>; using KeyType = MyString; template <typename K, typename V, typename H = boost::hash<K>, typename Eq = std::equal_to<K>> using SHMap = boost::unordered_map<K, V, H, Eq, Alloc<std::pair<K const, V>>>; using MySHMMap = SHMap<MyString, Data>;Now you can "simply" write:
mappa->emplace("value", Data{12, 1111});Instead of the complicated version before. Live On Coliru
Heterogenous Key Lookup
The other place where we are constructing
MyString(just to throw it away after theat()call...), we can useboost::unordered_map's compatible-key lookup:Data getValue(std::string_view key) const { auto it = mappa->find(key, mappa->hash_function(), mappa->key_eq()); return it != mappa->end() ? it->second : throw std::range_error("getValue"); }This requires the hash and equality to be compatible:
using MySHMMap = SHMap<MyString, Data, std::hash<std::string_view>, std::equal_to<std::string_view>>;See it Live On Coliru
Using C 20 standard unordered_map instead (see https://en.cppreference.com/w/cpp/container/unordered_map/find):
struct Hash : std::hash<std::string_view> { using is_transparent = std::true_type; }; struct Eq : std::equal_to<std::string_view> { using is_transparent = std::true_type; }; using MySHMMap = SHMap<MyString, Data, Hash, Eq>;And then:
Data getValue(std::string_view key) const { #ifdef __cpp_lib_generic_unordered_lookup auto it = mappa->find(key); #else auto it = mappa->find( MyString(key.data(), key.size(), segment.get_segment_manager())); #endif return it != mappa->end() ? it->second : throw std::range_error("getValue"); }See it Live On Coliru as well
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/440918.html
