Как удалить ключ из Poco JSON при его повторении? - PullRequest
0 голосов
/ 31 января 2019

Как мне удалить ключ из Poco json при его итерации?Например:

Poco::JSON::Object::Ptr poco_json;
for (auto& objs : *poco_json)
{
     // do something
     if (objs.first == "specific key")
         poco_json->remove(key);     
}

или

Poco::JSON::Object::Ptr poco_json;
for(auto it = poco_json->begin();it != poco_json->end();)
{
    // do something
    if (it->first == "specific key")
        it = poco_json->remove(it->first);//error : poco didn't have something like this
    else
        ++it;
}

проблема в том, что после удаления ключа из json он сделает недействительными итераторы.Я знаю, что в std :: map, erase возвращает действительный итератор для следующей итерации, но я не могу найти что-то похожее для Poco json.

Ответы [ 2 ]

0 голосов
/ 31 января 2019

Вы можете изменить этот код в Poco:

inline Iterator Object::remove(const std::string& key)
{
    auto ret_it = _values.erase(key);
    if (_preserveInsOrder)
    {
        KeyList::iterator it = _keys.begin();
        KeyList::iterator end = _keys.end();
        for (; it != end; ++it)
        {
            if (key == (*it)->first)
            {
                _keys.erase(it);
                break;
            }
        }
    }
    _modified = true;

  return ret_it;
}
0 голосов
/ 31 января 2019

std::map::erase возвращает итератор к следующему элементу начиная с C ++ 11, до c ++ 11 вы стираете элементы следующим образом:

for (auto it = m.begin(); it != m.end(); ) {
    if (it->first == someKey)
      m.erase(it++); // use post-increment,pass copy of iterator, advance it
    else 
      ++it;
  }

и вы можете сделать это аналогичным образом, стирая ключ изPoco::JSON::Object.Где вы читали, что remove делает недействительными итераторы?

Некоторый фрагмент кода из источника:

class JSON_API Object {
    typedef std::map<std::string, Dynamic::Var> ValueMap; // <--- map
    //...
    Iterator begin();
        /// Returns begin iterator for values.
    Iterator end();
        /// Returns end iterator for values.
    void remove(const std::string& key);
        /// Removes the property with the given key.

    ValueMap          _values; // <---

};

inline Object::Iterator Object::begin()
{
    return _values.begin();
}
inline Object::Iterator Object::end()
{
    return _values.end();
}

inline void Object::remove(const std::string& key)
{
    _values.erase(key); // <--- erase is called on map, so iteratos are not invalidated
    if (_preserveInsOrder)
    {
        KeyList::iterator it = _keys.begin();
        KeyList::iterator end = _keys.end();
        for (; it != end; ++it)
        {
            if (key == (*it)->first)
            {
                _keys.erase(it);
                break;
            }
        }
    }
    _modified = true;
}

Вы можете переписать ваш цикл в:

for(auto it = poco_json->begin();it != poco_json->end();)
{
    // do something
    if (it->first == "specific key")
    {
        auto copyIt = it++;
        poco_json->remove(copyIt->first);
    }
    else
        ++it;
}

EDIT Почему ваш код не работает в цикле Range-For:

for (auto& objs : *poco_json)
{
     // do something
     if (objs.first == "specific key")
         poco_json->remove(key);     
}

он переведен в

for (auto it = poco_json->begin(); it != poco_json->end(); ++it)
{
     // do something
     if (it->first == "specific key")
         poco_json->remove(it->first);     
    // remove is called, it is erased from inner map
    // ++it is called on iterator which was invalidated, 
    // code crashes
}
...