我有两个地图将User对象列表存储为值。这些值的键是uint32_t和SocketAddress结构,如下所示。
第一个地图插入值很好,但在调试时查看本地人,我可以看到第二个地图似乎根本没有插入值。这是相关的代码:
的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(地址)时,返回的用户没有用户!查看内存中的对,看起来地址存储为键,但不存储指向用户的指针。我不知道该怎么想!有人有什么想法吗?
编辑: 看起来下面的用户发现了一些问题,虽然看起来不是我的问题的原因。
在修复了操作符之后,我将问题分解为以下几行:
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
我不知道为什么。听起来像是另一个问题的工作。
答案 0 :(得分: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, b
的{{1}}个对象a < b
......
答案 1 :(得分:1)
您的operator<
错了。如果长度等于维持严格的弱排序,则只应比较.contents。如上所述,您可以使用两个A类的两个实例
使用if a not equal b return a less than b
模式编写脑死亡操作符&lt;。
答案 2 :(得分:1)
您对运算符<
的实现可能会比较超出长度的地址组件:
bool Socket::SocketAddress::operator<(const SocketAddress &source) const {
return (fromlen < source.fromlen || memcmp(&from, &source.from, fromlen) < 0);
}
由于||
会使评估发生短路,因此仅当memcmp
评估为fromlen < source.fromlen
时才会调用false
,这意味着fromlen >= source.fromlen
。< / p>
结果,memcmp
的调用将传递两个长度的更大,这意味着当两个地址的前缀最多source.fromlen
匹配时,{{ 1}}将比较地址有效部分之外的字节。
要解决此问题,您应该将memcmp
传递给source.fromlen
而不是memcmp
。
答案 3 :(得分: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