Обход постоянных элементов Boost Multi-Index контейнера - PullRequest
2 голосов
/ 03 апреля 2011

У меня есть некоторый класс данных, который стоит скопировать, но он должен быть изменяемым, поскольку он часто обновляется в соответствии с событиями.Мне также нужен многоиндексный контейнер для хранения многих таких классов.Я пытаюсь настроить его, используя boost :: multi_index.Например:

struct MutableAndExpensiveToCopy {
    int some_value;
    std::map<int, std::string> some_huge_map;
    std::map<int, std::string> an_even_bigger_map;
}

struct CanBeMultiIndexed
{
    // "Payload" - its fields will never be used as indices
    MutableAndExpensiveToCopy data;

    // Indexes        
    int         id;
    std::string label;
}

typedef multi_index_container<
    CanBeMultiIndexed,
    indexed_by<
        ordered_unique<member<CanBeMultiIndexed, int, &CanBeMultiIndexed::id>>,
        ordered_non_unique<member<CanBeMultiIndexed,std::string,&CanBeMultiIndexed::label>>
    > 
> MyDataContainer;

Моя проблема в том, что multi_index рассматривает элементы в контейнере как константы (чтобы сохранить целостность всех индексов).Например, следующее не будет компилироваться:

void main() {
    // put some data in the container
    MyDataContainer container;
    CanBeMultiIndexed e1(1, "one"); // conto'r not shown in class definition for brevity
    CanBeMultiIndexed e2(2, "two");

    container.insert(e1);
    container.insert(e2);

    // try to modify data
    MyDataContainer::nth_index<1>::type::iterator iter = container.get<1>().find(1);
    iter->data.some_value = 5;  // constness violation
}

Я не могу использовать метод replace(), так как копирование класса полезной нагрузки обходится дорого.Я знаю о методе modify(), но его использование кажется громоздким, поскольку в моей реальной программе класс «полезной нагрузки» может содержать множество полей, и для каждого из них исключается написание функтора.

Есть предложения?

РЕДАКТИРОВАТЬ: После некоторой игры я попытался заменить элемент данных с shared_ptr на MutableAndExpensiveToCopy:

struct CanBeMultiIndexed
{
    // "Payload" - its fields will never be used as indices
    boost::shared_ptr<MutableAndExpensiveToCopy> data;

    // Indexes        
    int         id;
    std::string label;
}

Это сработало, и я смог скомпилировать main(), включая код для изменения данных:

void main() {
    ...
    iter->data->some_value = 5;  // this works
    ...
}

Это в значительной степени дает мне то, что я хотел, но я не уверен, почему это работает, поэтому:

  1. Этот код выполняет то, что я хотел, или есть какое-то предостережение, которое я пропускаю?
  2. Как это работает?Разве константа shared_ptr не применяется к его оператору ->?

1 Ответ

4 голосов
/ 03 апреля 2011

Прежде всего, ImMutableAndExpensiveToCopy кажется совершенно противоположным --mutable, так как вы пытаетесь изменить его содержимое в примере.Попробуйте просто так:

struct CanBeMultiIndexed
{
    mutable ImMutableAndExpensiveToCopy data;
    int         id;
    std::string label;
}

(и, возможно, измените имя ImMutableAndExpensiveToCopy для согласованности.)

...