skip to Main Content

I’ve written a long and complicated server program on windows. Used visual studio 2019.

Then I’ve created a CentOS 8 operating system on vm virtualbox and transferred all the code there. And rebuilt an executable with visual code. That works okay except one part.

Here is the code that causes the crash:

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

this works without any bug on windows(compiled with visual studio 2019)

but gives this error on centos 8 (compiled with visual code / g++)

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

But if I put break; right after client.erase(i); problem is solved.

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

So problem is caused when for loop iterates after deleting something from clients.

The question is :

Why does it solve this problem automatically, without breaking out of the loop on the code compiled on windows but cannot solve it on centos 8 ?

3

Answers


  1. for (const auto& kv : clients) {
    

    This iterates over the range using iterators. After the loop body is executed each time, the iterator is incremented.

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

    This invalidates the current iterator. When the invalid iterator is incremented after the loop body, the behaviour of the program is undefined.


     break;//this line makes it work.
    

    Why does it solve this problem

    Because when you break out of the loop before the invalid iterator is incremented, there is no undefined behaviour.

    Login or Signup to reply.
  2. I agree with @eerorika. Also, your break statement breaks out of the loop. Without it, the loop continues executing after your if statement gets a true condition. That’s a very different action. Is your loop intended to delete only one client at a time?

    Login or Signup to reply.
  3. Unless you only want to erase the first timed-out client, instead of all timed-out clients (which is more likely), then there is a bug in your code.

    Is this what you intended?:

    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;
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search