Удаление значения из мультикарты

Мое требование состоит в том, чтобы удалить «значение» из мультикарты, а не «ключ». Ключ может иметь несколько значений, и i нужно удалить конкретное значение. Мое требование аналогично удалению узла из связанного списка.

Я делаю это, используя метод multimap::erase(). Но после удаления, если я попытаюсь распечатать значения мультикарты, значения, удаленные с помощью multimap::erase(), также будут напечатаны.

ниже мой фрагмент кода:

void Clientqueues::clearSubscription(string name,string sessionid)
{
    pair<multimap<string,string>::iterator,multimap<string,string>::iterator> i;
    multimap<string, string>::iterator j;
    i = registeredClientInfo.equal_range(name);

    if (j == registeredClientInfo.end())
            return;
    for(j=i.first;j != i.second;++j)
    {
        if((j->second) == sessionid) registeredClientInfo.erase(j->second);
    }

    for(j=i.first;j != i.second;++j)
    {
        cout<<""<<j->second<<endl;///This prints the erased values too;
    }

}

Я делаю что-то неправильно? Любая помощь в этом отношении очень ценится.


person user1081481    schedule 05.12.2011    source источник


Ответы (2)


Самое главное, вы звоните erase(j->second), хотя хотели позвонить erase(j). Вы не стираете элемент мультикарты, на который указывает j, вы стираете все элементы, чьи ключи равны значению элемента, на который указывает j (то есть sessionid). Я ожидаю, что это ничего.

Кроме того: вызовите equal_range снова после завершения цикла erase - эффект использования стертого итератора не определен, поэтому, если вы стерли первый итератор i.first, вы не сможете снова начать итерацию оттуда после этого.

Обратите внимание, что это также означает, что в вашем цикле есть ошибка, которая делает erase, поскольку в случае, когда вы вызываете erase, вы увеличиваете j, когда он содержит значение итератора, которое больше не действительно. К сожалению, правильный код:

for(j=i.first;j != i.second;)
{
    if((j->second) == sessionid) {
        auto next = j;
        ++next;
        registeredClientInfo.erase(j);
        j = next;
    } else {
        ++j;
    }
}

Или, если вы предпочитаете:

for(j=i.first;j != i.second;)
{
    auto current = j;
    ++j;
    if((current->second) == sessionid) registeredClientInfo.erase(current);
}

Или, если запись уникальна для пары ключ/значение, так что вам нужно удалить только одну вещь, тогда:

for(j=i.first;j != i.second;++j)
{
    if((j->second) == sessionid) {
        registeredClientInfo.erase(j);
        break;
    }
}

if (j == registeredClientInfo.end()) return; тоже не подходит, так как j не инициализируется, когда вы это делаете. Если ключ не найден, то equal_range возвращает пустой диапазон (два одинаковых значения итератора), поэтому другие ваши циклы все равно ничего не сделают.

person Steve Jessop    schedule 05.12.2011

Если вы удалили i.first или i.second, итераторы становятся недействительными, что подразумевает неопределенное поведение.

person Krizz    schedule 05.12.2011