1

User オブジェクトのリストを値として格納する 2 つのマップがあります。これらの値のキーは、以下に定義されている uint32_t および SocketAddress 構造体です。

最初のマップでは問題なく値が挿入されますが、デバッグ中にローカルを確認すると、2 番目のマップでは値がまったく挿入されていないように見えます。関連するコードは次のとおりです。

ソケットアドレス:

struct SocketAddress {
    sockaddr from;
    socklen_t fromlen;
    SocketAddress& operator=(const SocketAddress &source);
    bool operator==(const SocketAddress &source) const;
    bool operator!=(const SocketAddress &source) const;
    bool operator<(const SocketAddress &source) const;
    bool operator>(const SocketAddress &source) const;
    bool operator<=(const SocketAddress &source) const;
    bool operator>=(const SocketAddress &source) const;
};

Socket::SocketAddress& Socket::SocketAddress::operator=(const SocketAddress &source) {
    memcpy(&from, &source.from, source.fromlen);
    fromlen = source.fromlen;
    return *this;
}

bool Socket::SocketAddress::operator==(const SocketAddress &source) const {
    return (fromlen == source.fromlen && memcmp(&from, &source.from, fromlen) == 0);
}
bool Socket::SocketAddress::operator!=(const SocketAddress &source) const {
    return !this->operator==(source);
}
bool Socket::SocketAddress::operator<(const SocketAddress &source) const {
    return (fromlen < source.fromlen || memcmp(&from, &source.from, fromlen) < 0);
}
bool Socket::SocketAddress::operator>(const SocketAddress &source) const {
    return (fromlen > source.fromlen || memcmp(&from, &source.from, source.fromlen) > 0);
}
bool Socket::SocketAddress::operator<=(const SocketAddress &source) const {
    return !this->operator>(source);
}
bool Socket::SocketAddress::operator>=(const SocketAddress &source) const {
    return !this->operator<(source);
}

ユーザー コンストラクターと関連する変数:

std::map<uint32_t, std::shared_ptr<User>> User::_usersListBySession;
std::map<Socket::SocketAddress, std::shared_ptr<User>> User::_userListByAddress;
std::atomic<unsigned int> User::_nextSessionID = 0;

User::User(const Socket::SocketAddress& addr) {
    address = addr;

    sessionID = ++_nextSessionID;

            // This seems to work just fine
    _usersListBySession.insert(std::pair<uint32_t, std::shared_ptr<User>>(sessionID, std::shared_ptr<User>(this)));
            // This does not
    _userListByAddress.insert(std::pair<Socket::SocketAddress, std::shared_ptr<User>>(addr, std::shared_ptr<User>(this)));
}

住所の定義:

    const Socket::SocketAddress& address

意図したとおりに動作しないコードのセグメント。

    std::shared_ptr<User> user = User::getUserWithAddress(address);
    if (!user) {
        user = std::shared_ptr<User>(new User(address));
    }

マップ検索機能:

std::shared_ptr<User> User::getUserWithAddress(const Socket::SocketAddress& addr) {
    return _userListByAddress[addr];
}

std::shared_ptr<User> User::getUserWithSessionID(uint32_t sessionid) {
    return _usersListBySession[sessionid];
}

User::getUserWithAddress(address) を呼び出すと、返されたユーザーにユーザーがいません! メモリ内のペアを見ると、アドレスがキーとして格納されているように見えますが、ユーザーへのポインタは格納されていません。私は何を考えるべきかわからない!誰にもアイデアはありますか?


編集:以下のユーザーによって特定されたいくつかの問題があったようですが、それが私の問題の原因ではないようです.

演算子を修正した後、問題を次の行に切り分けました。

assert(this->address == addr);
_userListByAddress.insert(std::pair<Socket::SocketAddress, std::shared_ptr<User>>(addr, std::shared_ptr<User>(this)));
assert(this->address == addr);

最初のアサーションは成功し、2 番目のアサーションは失敗します。


編集#2:

これを行うことで問題を解決したようです:

std::shared_ptr<User> user(this);
_usersListBySession.insert(std::pair<uint32_t, std::shared_ptr<User>>(sessionID, user));
assert(this->address == addr); // works
_userListByAddress.insert(std::pair<Socket::SocketAddress, std::shared_ptr<User>>(addr, user));
assert(this->address == addr); // works

理由がわかりません。別の質問の仕事のように聞こえます。

4

4 に答える 4

4

この実装は正しくありません:

bool Socket::SocketAddress::operator<(const SocketAddress &source) const {
    return (fromlen < source.fromlen || memcmp(&from, &source.from, fromlen) < 0);
}

考えられる正しい方法の 1 つは次のとおりです。

bool Socket::SocketAddress::operator<(const SocketAddress &source) const {
    if (fromlen < source.fromlen) return true;
    else if (fromlen > source.fromlen) return false;
    //else: fromlen == source.fromlen
    return (memcmp(&from, &source.from, fromlen) < 0);
}

強い順序付けを意味しないため、実装は正しくありません。同時に2つのSockedAddrオブジェクトを簡単に見つけることができます:そして...a, ba < bb < a

于 2012-11-24T19:01:27.777 に答える
1

あなたoperator<は間違っています。厳密な弱順序を維持するために長さが等しい場合にのみ、.contentsを比較する必要があります。書かれているように、両方のAを持つクラスの2つのインスタンスを持つことができます

このパターンを使用して、if a not equal b return a less than bブレインデッドオペレーター<を記述します。

于 2012-11-24T19:03:34.583 に答える
1

演算子の実装は<、長さを超えるアドレスコンポーネントを比較している可能性があります。

bool Socket::SocketAddress::operator<(const SocketAddress &source) const {
    return (fromlen < source.fromlen || memcmp(&from, &source.from, fromlen) < 0);
}

||評価を短絡するため、の呼び出しは、に評価されmemcmpた場合にのみ行われます。つまり、。fromlen < source.fromlenfalsefromlen >= source.fromlen

その結果、の呼び出しは2つの長さの大きい方memcmpを渡します。つまり、両方のアドレスのプレフィックスが一致すると、アドレスの有効な部分を超えるバイトが比較されます。source.fromlenmemcmp

これを修正するには、の代わりにに渡す必要がsource.fromlenありmemcmpますfromlen

于 2012-11-24T19:04:45.273 に答える
0

これを行うことで問題を解決したようです(上記の他の役立つコメントに加えて):

std::shared_ptr<User> user(this);
_usersListBySession.insert(std::pair<uint32_t, std::shared_ptr<User>>(sessionID, user));
assert(this->address == addr); // previously works, still works
_userListByAddress.insert(std::pair<Socket::SocketAddress, std::shared_ptr<User>>(addr, user));
assert(this->address == addr); // previously fails, now works
于 2012-11-24T23:18:24.287 に答える