I have two maps to store a list of User objects as values. The keys for those values are a uint32_t and a SocketAddress struct as defined below.
The first map inserts values just fine but looking at the locals while debugging, I can see that the second doesn’t seem to insert values at all. Here’s the relevant code:
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);
}
User Constructor and associated variables:
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)));
}
Definition of address:
const Socket::SocketAddress& address
Segment of code that doesn’t operate as intended.
std::shared_ptr<User> user = User::getUserWithAddress(address);
if (!user) {
user = std::shared_ptr<User>(new User(address));
}
Map search functions:
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];
}
When making the call to User::getUserWithAddress(address), the user returned has no user! Looking at the pair in memory, it looks like the address is stored as a key, but no pointer to the user is stored. I’m not sure what to think! Anyone have any ideas?
Edit:
It looks like there were a few problems identified by the users below though it doesn’t look like that was the cause of my problems.
After fixing the operators, I’ve isolated the issue down to these lines:
assert(this->address == addr);
_userListByAddress.insert(std::pair<Socket::SocketAddress, std::shared_ptr<User>>(addr, std::shared_ptr<User>(this)));
assert(this->address == addr);
The first assertion passes, the second fails.
Edit #2:
Looks like I’ve solved the issue by doing this:
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
I have no idea why. Sounds like a job for another question.
This implementation is not correct:
One possible correct way is:
Your implementation is not correct because it does not imply strong ordering, you can easily find two
SockedAddrobjectsa, bwhich are at the same time:a < bandb < a…