我目前正在使用自定义键创建自定义std :: unordered_map声明:
class BASE_DLLSPEC ClientKey
{
private:
// this is always true initially until we call SetClientId
bool emptyId;
// both of these are guaranteed to be unique
QString m_connectId; // ip:port format
QString m_clientId; // {Uuid} format
// ----------
public:
ClientKey(const QString& connectId = "", const QString& clientId = "") :
emptyId(true), m_connectId(connectId), m_clientId(clientId)
{ }
void SetClientId(const QString& clientId)
{
m_clientId = clientId;
emptyId = false;
}
const QString& GetConnectId() const { return m_connectId; }
const QString& GetClientId() const { return m_clientId; }
bool operator==(const ClientKey& other) const
{
int comp1 = QString::compare(m_connectId, other.GetConnectId());
int comp2 = QString::compare(m_clientId, other.GetClientId());
return (comp1 == 0) ||
(!emptyId && comp2 == 0);
}
};
struct BASE_DLLSPEC ClientKeyHash
{
std::size_t operator()(const ClientKey& key) const
{
std::string connectId = key.GetConnectId().toStdString();
std::string clientId = key.GetClientId().toStdString();
std::size_t h1 = std::hash<std::string>()(connectId);
std::size_t h2 = std::hash<std::string>()(clientId);
return h1 ^ (h2 << 1);
}
};
struct BASE_DLLSPEC ClientKeyEqual
{
bool operator()(const ClientKey& lhs, const ClientKey& rhs) const
{
return lhs == rhs;
}
};
typedef std::unordered_map<ClientKey,
ClientPtr,
ClientKeyHash,
ClientKeyEqual> ClientMap;
我在迭代期间遇到特定密钥时遇到困难。出于某种原因,当我传入一个用于查找的键时,我的客户端对象永远不会找到。
ClientKey key = Manager::ClientKey(connectId);
ClientManager& clientManager = Manager::ClientManager::GetInstance();
ClientMap::const_iterator clientIter = clientManager.GetClients().find(key);
即使已插入密钥,clientIter也始终指向结束迭代器位置。您是否认为这与必须在堆栈上重新创建这些ClientKey值然后将它们传递到地图以进行查找有关,或者我在其他地方遇到问题?感谢您的澄清和见解。
答案 0 :(得分:0)
首先,对emptyId字段的一些注意事项(不要考虑无效格式 - 顺便说一下,你也没有检查过):
ClientKey k0("hello", "world");
ClientKey k1("hello");
k1.SetClientId("world");
对于k0和k1,emtpyId标志是否有任何特殊原因?我个人会说:
m_clientId.empty()
获得相同的信息。现在失败的原因:
再次考虑k0
和k1
,但没有在k1上调用过SetClientId:
ClientKey k0("hello", "world");
ClientKey k1("hello");
想象一下k0
已插入地图中,而k1
则会尝试找到它。会发生什么? k1生成另一个散列键而不是k0,并且映射将查看与k0所在位置不同的桶 - 并且不会找到任何内容。
我认为您想要实现的是为同一连接ID提供多个客户端,并且能够针对给定的连接ID迭代这些客户端。所以您可能更喜欢std::unordered_multimap<std::string, ClientPtr>
(其中string参数表示连接ID)。您将通过equal_range
获取给定连接ID的所有客户,然后您的班级ClientKey
就会过时。
答案 1 :(得分:0)
您的代码允许以下内容返回true:
ClientKey k1("hello", "world");
ClientKey k2("hello", "");
return k1 == k2;
但是,您的哈希基于connectId和clientId的组合。
unordered_map::find
没有对地图进行详尽的搜索,而是在存储桶中查找给定的哈希值,并将只是条目中的条目进行比较。
您仅使用connectId
生成测试密钥,因此它会查找ClientKey(connectId, "")
而不是ClientKey(connectId, someOtherValue)
的存储区。
您应该考虑专门根据connectId
制作哈希值。
最后,请注意您的构造函数:
ClientKey(const QString& connectId = "", const QString& clientId = "") :
emptyId(true), m_connectId(connectId), m_clientId(clientId)
{ }
如果我写:
ClientKey ck("hello");
emptyId
真的应该是真的吗?