为什么这段代码在一个平台上有效,但在另一个平台上却不起作用?
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;
}
我在 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;
}