2016-07-13 2 views
0

キーカスタムとunordered_map:私は私の反復中の特定のキーを見つけるの困難を抱えている検索キー::私は現在、私のカスタムキーとカスタムの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

私はあなたのクライアントキーのハッシュ関数を実装していませんが、それはおそらく問題です。この回答を参照してください:http://stackoverflow.com/questions/17016175/c-unordered-map-using-a-custom-class-type-as-the-key –

+2

それはあなたが等しいと比較するキーが異なるハッシュこれはおそらくうまくいかない。 –

答えて

0

、emptyIdフィールド(無効な形式を考慮していない - の方法により、どちらかによって確認されていない)にはいくつかの注意事項:

ClientKey k0("hello", "world"); 
ClientKey k1("hello"); 
k1.SetClientId("world"); 

はemtpyId任意の特定の理由がありますフラグはk0とk1で異なるはずですか?私は個人的に言うでしょう:

  1. フラグは正しく実装されていません。
  2. これは冗長です。m_clientId.empty()で同じ情報が得られます。

は今、失敗の理由は:

は再びk0と​​考えてみましょう、しかしSETCLIENTIDなしK1で呼び出された:

ClientKey k0("hello", "world"); 
ClientKey k1("hello"); 

k0を想像してみてはマップに挿入されている、と​​とあなたはそれを見つけようとします。何が起こるか? k1はk0よりも別のハッシュキーを生成し、マップはk0が存在する場所とは異なるバケットを検索し、何も見つけられません。

あなたが達成したいと思うのは、同じ接続IDに対して複数のクライアントを持ち、指定された接続IDに対してこれらの値を繰り返し処理できることです。したがって、std::unordered_multimap<std::string, ClientPtr>(文字列パラメータは接続IDを表します)を使用することをお勧めします。指定された接続IDのすべてのクライアントをequal_range経由で取得し、クラスClientKeyは時代遅れになります。

ClientKey k1("hello", "world"); 
ClientKey k2("hello", ""); 
return k1 == k2; 

しかし、あなたのハッシュがconnectIdとのclientIdの組み合わせに基づいています。

+0

それが実際に私がこの問題に遭遇した理由です。どうもありがとうございました。私はまず、connectIdを空のclientIdで渡します。ここで私はfindを実行します。クライアントIDを設定している新しいクライアントの場合はそれに続きます。だから、再イテレーションでは、clientIdは常に空であり、現在の状態では、ハッシュはfindでclientIdも利用します。 – m11hut

0

あなたのコードは次のようにtrueを返しますことができます。

unordered_map::findマップの完全な検索を行わず、指定されたハッシュをバケット内で検索し、だけをバケット内のエントリと比較します。

connectIdでテストキーを生成しているので、ClientKey(connectId, someOtherValue)のバケットではなく、ClientKey(connectId, "")のバケットを探しています。

ハッシュのみをconnectIdに基づいて作成することを検討する必要があります。

最後に、あなたのコンストラクタの点に注意してください。

ClientKey(const QString& connectId = "", const QString& clientId = "") : 
    emptyId(true), m_connectId(connectId), m_clientId(clientId) 
{ } 

私が書く場合:

ClientKey ck("hello"); 

emptyId本当すべきですか?

関連する問題