1

我有两个映射来将用户对象列表存储为值。这些值的键是 uint32_t 和 SocketAddress 结构,如下定义。

第一张地图插入值很好,但在调试时查看本地人,我可以看到第二张地图似乎根本没有插入值。以下是相关代码:

套接字地址:

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:

看起来我已经通过这样做解决了这个问题:

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);
}

一种可能的正确方法是:

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);
}

您的实现不正确,因为它并不意味着强排序,您可以轻松找到同时存在的两个SockedAddr对象a, ba < b并且b < a...

于 2012-11-24T19:01:27.777 回答
1

operator<错了。如果长度相等,您应该只 compare.contents 以保持严格的弱排序。如所写,您可以有两个具有 A 的类的实例

使用该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

结果,调用memcmp将传递两个长度中较大的一个,这意味着当两个地址的前缀source.fromlen匹配时,memcmp将比较地址有效部分之外的字节。

要解决此问题,您应该传递source.fromlentomemcmp而不是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 回答