c++ - 以结构为键的 std::map 未按预期工作

标签 c++ struct stdmap

<分区>

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

第一个 map 可以很好地插入值,但在调试时查看局部变量,我可以看到第二个 map 似乎根本没有插入值。这是相关代码:

套接字地址:

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

map 搜索功能:

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

我不知道为什么。听起来像是另一个问题的工作。

最佳答案

这个实现是不正确的:

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同时是:a < bb < a ...

关于c++ - 以结构为键的 std::map 未按预期工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13544466/

相关文章:

c++ - 重载函数模板和继承参数

结构构造函数或初始化

memory - OpenCL:如何将全局内存的连续 block 复制到私有(private)内存?

c++ - 模板类型参数的模板参数必须是一个类型

c++ - 绑定(bind)类方法到线程

c++ - 设置 boost 并与 Visual Studio 2010 Express 一起使用

c++ - 使用 vector 的合并排序 C++

c - C中struct的动态分配

c++ - O(log n) 索引更新和搜索

c++ - OMP 和 std::set<...>::iterator 上的并行操作