为什么这段代码在一个平台上有效,但在另一个平台上却不起作用?

Why does this code works on one platform but doesn't work on another?

我在 windows 上写了一个又长又复杂的服务器程序。二手 visual studio 2019.

然后我在 vm virtualbox 上创建了一个 CentOS 8 操作系统并将所有代码转移到那里。并用可视代码重建了一个可执行文件。除了一部分以外,一切正常。

这是导致崩溃的代码:

//clients is    std::map<int, boost::shared_ptr<Client>> clients;

        for (const auto& kv : clients) {
            
            int elapsed_seconds = boost::chrono::duration_cast<boost::chrono::seconds>(timeNow - kv.second->lastUpdated).count();

            int i = kv.first;

            if (elapsed_seconds >= ServerData::SessionTimeoutSeconds)
            {
                trash_bin.push_back(clients[i]);
                clients.erase(i);
            }
        }

这在 windows 上没有任何错误(使用 visual studio 2019 编译)

但在 centos 8 上出现此错误(使用可视代码/g++ 编译)

Assertion `px != 0' failed. Aborted (core dumped)

但是如果我把 break;在 client.erase(i) 之后;问题解决了。

if (elapsed_seconds >= ServerData::SessionTimeoutSeconds)
{
    trash_bin.push_back(clients[i]);
    clients.erase(i);
    break;//this line makes it work.
}

所以当for循环从客户端删除某些内容后进行迭代时会导致问题。

问题是:

为什么在windows上编译的代码自动解决了这个问题,没有跳出循环,但在centos 8上却无法解决?

for (const auto& kv : clients) {

这使用迭代器迭代范围。每次执行完循环体后,迭代器自增

int i = kv.first;
clients.erase(i);

这会使当前迭代器无效。当无效迭代器在循环体后递增时,程序的行为是未定义的。


 break;//this line makes it work.

Why does it solve this problem

因为当您在无效迭代器递增之前跳出循环时,没有未定义的行为。

我同意@eerorika。此外,您的 break 语句会跳出循环。没有它,循环会在您的 if 语句获得 true 条件后继续执行。这是一个非常不同的动作。您的循环是打算一次只删除一个客户端吗?

除非你只想删除第一个个超时客户端,而不是所有个超时客户端(这更有可能),则说明您的代码中存在错误。

这是你想要的吗?:

auto kv = clients.begin();
while (kv != clients.end()) {
    int elapsed_seconds = boost::chrono::duration_cast<boost::chrono::seconds>
                                     (timeNow - kv->second->lastUpdated).count();
    if (elapsed_seconds >= ServerData::SessionTimeoutSeconds) {
        trash_bin.push_back(*kv);
        kv = clients.erase(kv);
    }
    else
        ++kv;
}