boost multi_index_container изменение ключей -> неверное состояние контейнера

Предположим, у нас есть мультииндексный контейнер:

#include <iostream>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <boost/multi_index/tag.hpp>
#include <boost/multi_index/key_extractors.hpp>

struct A{
A(int i){id=i;}
    int id;
};

typedef boost::multi_index::multi_index_container<
    A * ,
    boost::multi_index::indexed_by<
        boost::multi_index::random_access<
            boost::multi_index::tag<by_insertion>
        >, // this index represents insertion order
        boost::multi_index::hashed_unique<
            boost::multi_index::tag<by_id>,
            boost::multi_index::member<A, int, &A::id>
        >
    >
> MapType;

MapType map;

map.get<1>().insert(new A(1));
map.get<1>().insert(new A(2));

(*map.get<1>().find(1))->id=4; // HERE IF I CHANGE THE KEY, I CAN NOT FIND either key=4 or 1

MapType::nth_index<1>::type::iterator it = map.get<1>().find(4);
if(it != map.get<1>().end() ){
    std::cout << "FOUND A:" << *it << std::endl;
} // DOES NOT WORK?? WHY CANT I FIND the ELement with Key 4?

Проблема в том, что я, вероятно, неправильно настроил boost::multi_index::member<A, int, &A::a>, потому что, когда я меняю какой-либо ключ. Я не могу найти элемент с ключом = 4?

Что здесь используется неправильно? Любая помощь действительно ценится!


person Gabriel    schedule 25.07.2013    source источник
comment
Подождите: вы меняете значение, которое вы ищете на карте, и ожидаете, что карта волшебным образом узнает об этом? Как правило, изменение объекта поиска в контейнере без уведомления контейнера приводит к UB.   -  person Yakk - Adam Nevraumont    schedule 25.07.2013


Ответы (2)


Нет, хешированные индексы не хранят хеш-значения, они всегда вычисляют его на лету. Почему вы хотите изменить ключи, но продолжаете искать старые значения?

person Joaquín M López Muñoz    schedule 25.07.2013
comment
Так почему я не могу найти элемент с ключом = 4 MapType::nth_index<1>::type::iterator it = map.get<1>().find(4); if(it != map.get<1>().end() ){ std::cout << "FOUND A:" << *it << std::endl; } это не сработает! - person Gabriel; 25.07.2013
comment
Потому что элемент хранится так, как если бы ключ = 1. Вот что происходит: * Если вы ищете 4, вы окажетесь в пустом ведре. * Если вы ищете 1, вы обнаруживаете элемент, но при проверке ключа это 4, поэтому поиск также не работает. - person Joaquín M López Muñoz; 25.07.2013
comment
И, повторяя мой вопрос: зачем вам это? - person Joaquín M López Muñoz; 25.07.2013
comment
Спасибо за это замечательное объяснение! Я не хочу менять ключ, но основная проблема заключается в том, что если я помещаю указатели в контейнер только тогда, я могу изменять элементы (контейнер имеет доступ только для чтения, делая все отложенные итераторы типа A* константными, где это возможно чтобы изменить базовый экземпляр A ), но тогда я могу изменить ключ, на котором основан мой контейнер, если этот ключ не является постоянным в классе A. Разве это не глупо? - person Gabriel; 26.07.2013

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

  • Используйте modify(), который проверяет, нужно ли перемещать измененный элемент в результате нажатия какой-либо клавиши.
  • Если вы знаете, что не будете менять тональность, используйте const_cast<A&>() и изменяйте по своему усмотрению.

В общем, Boost.MultiIndex не имеет возможности предоставить доступ на запись только к неключевым частям элемента.

person Joaquín M López Muñoz    schedule 28.07.2013
comment
Jeah, извините за вводящее в заблуждение описание: я хотел бы иметь указатели в этом контейнере, я делаю это не для того, чтобы иметь возможность изменять объекты. Это немного тонко, но в моем тесте выше я иногда обходил тот факт, что контейнер должен предоставлять только постоянный доступ, что он и делает, но не влияет на указатель. так что была моя проблема. Мой ключ в любом случае должен быть постоянным const A::id в классе, поэтому указатель на A в порядке. Использование modify() является одним из вариантов, но это немного громоздко. - person Gabriel; 29.07.2013
comment
Другой вариант — собрать указатель на A и key в новый класс Data. - person Gabriel; 29.07.2013