C++ 为什么这段代码在一个平台上工作,但在另一个平台上不工作?
我在windows上编写了一个长而复杂的服务器程序。使用visual studio 2019 然后,我在vm virtualbox上创建了一个CentOS 8操作系统,并在那里传输了所有代码。并用可视化代码重建可执行文件。除了一个部分外,其他都可以 以下是导致崩溃的代码:C++ 为什么这段代码在一个平台上工作,但在另一个平台上不工作?,c++,visual-studio-code,boost,visual-studio-2019,centos8,C++,Visual Studio Code,Boost,Visual Studio 2019,Centos8,我在windows上编写了一个长而复杂的服务器程序。使用visual studio 2019 然后,我在vm virtualbox上创建了一个CentOS 8操作系统,并在那里传输了所有代码。并用可视化代码重建可执行文件。除了一个部分外,其他都可以 以下是导致崩溃的代码: //clients is std::map<int, boost::shared_ptr<Client>> clients; for (const auto& kv :
//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);
}
}
所以,当for循环在从客户机中删除某些内容后进行迭代时,就会出现这个问题
问题是:
为什么它会自动解决这个问题,而不会中断windows上编译的代码的循环,但无法在centos 8上解决它
这将使用迭代器在范围内进行迭代。每次执行循环体后,迭代器将递增
这将使当前迭代器无效。当无效迭代器在循环体之后递增时,程序的行为是未定义的
为什么它能解决这个问题
因为当您在无效迭代器递增之前中断循环时,没有未定义的行为
这将使用迭代器在范围内进行迭代。每次执行循环体后,迭代器将递增
这将使当前迭代器无效。当无效迭代器在循环体之后递增时,程序的行为是未定义的
为什么它能解决这个问题
因为当您在无效迭代器递增之前中断循环时,没有未定义的行为。我同意@eerorika。此外,您的break语句会跳出循环。如果没有它,循环将在if语句获得true条件后继续执行。那是一个非常不同的动作。您的循环是否打算一次只删除一个客户端?我同意@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;
}
除非您只想删除第一个超时客户端,而不是更可能的所有超时客户端,否则您的代码中会有一个bug 这是你想要的吗
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;
}
收集每个要擦除的元素,在for循环后从客户端擦除这些元素收集每个要擦除的元素,在for循环后从客户端擦除这些元素谢谢我的朋友。但我已经理解了这一部分。我想问的是,为什么在使用visual studio 2019在windows上编译代码时,即使我不使用break,它的工作方式也会有所不同;但在centos 8上使用可视化代码和g++不起作用。@uterian我已经告诉过你:程序的行为是未定义的。所以这不像不同的编译器处理循环的方式不同,只是随机的?@uterian它是未定义的行为。它不能保证是随机的。本课程的任何行为都不能保证。优秀且耐心地与课程理念对抗。做得好。这个实现是任何C++程序员必须实现的突破。谢谢我的朋友。但我已经理解了这一部分。我想问的是,为什么在使用visual studio 2019在windows上编译代码时,即使我不使用break,它的工作方式也会有所不同;但在centos 8上使用可视化代码和g++不起作用。@uterian我已经告诉过你:程序的行为是未定义的。所以这不像不同的编译器处理循环的方式不同,只是随机的?@uterian它是未定义的行为。它不能保证是随机的。本课程的任何行为都不能保证。优秀且耐心地与课程理念对抗。做得好。这个实现是任何C++程序员必须实现的突破性的。谢谢你,但是我问的不是它为什么会出错。我知道原因。但我不明白为什么它在不同的平台上表现不同。另外,不,该循环不应该一次只删除一个客户端。这一突破;这是一个短期的解决方案,如果需要的话,我会在以后替换整个代码。可能会有显著的实现差异。我怀疑您对擦除的调用可能会使随后重新访问的迭代器无效。实现上的差异可能决定了静默失败和崩溃之间的区别。我在精神上抓住了救命稻草,但我会用调试器来调查这种可能性。要意识到的重要一点是,即使在它似乎可以工作的平台上,它也可能工作10年,然后突然决定吃掉你的小狗并发射核导弹。[或者,更现实地说,会导致无声数据损坏,您只有在重写备份后才会注意到这一点]谢谢您,但我想问的不是为什么会出现错误。我知道原因。但我不下手
为什么它在不同的平台上表现不同。另外,不,该循环不应该一次只删除一个客户端。这一突破;这是一个短期的解决方案,如果需要的话,我会在以后替换整个代码。可能会有显著的实现差异。我怀疑您对擦除的调用可能会使随后重新访问的迭代器无效。实现上的差异可能决定了静默失败和崩溃之间的区别。我在精神上抓住了救命稻草,但我会用调试器来调查这种可能性。要意识到的重要一点是,即使在它似乎可以工作的平台上,它也可能工作10年,然后突然决定吃掉你的小狗并发射核导弹。[或者,更现实地说,导致只有在重写备份后才会注意到的无声数据损坏]或者使用std::erase_if@eerorika是的,如果你有C++ 20编译器,或者使用STD::if@eerorika是的,如果你有一个C++ 20编译器。
int i = kv.first;
clients.erase(i);
break;//this line makes it work.
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;
}