Как обойти константные элементы контейнера Boost Multi-Index

У меня есть некоторый класс данных, который дорого копировать, но он должен быть изменчивым, так как он часто обновляется в соответствии с событиями. Мне также нужен контейнер с несколькими индексами для хранения многих таких классов. Я пытаюсь настроить его с помощью 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(), но его использование кажется громоздким, так как в моей реальной программе класс "полезной нагрузки" может содержать множество полей, и о написании функтора для каждого из них не может быть и речи.

Какие-либо предложения?

EDIT: Немного поигравшись, я попытался заменить элемент данных с помощью 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 к его оператору ->?

person bavaza    schedule 03.04.2011    source источник


Ответы (1)


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

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

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

person Joaquín M López Muñoz    schedule 03.04.2011
comment
@ Хоакин - ImMutableAndExpensiveToCopy я хотел сказать, что меняю и дорого копирую. Я исправлю пример, чтобы было понятно. - person bavaza; 03.04.2011
comment
ОК, теперь я понял :-) В любом случае, mutable- квалификация решает вашу проблему? - person Joaquín M López Muñoz; 03.04.2011
comment
@ Хоакин - нет. Как указано в документации, итератор вернулся из, например find() по определению является константой. Это делается для того, чтобы гарантировать целостность индекса. Кстати, AFAIK, члены класса/структуры по умолчанию изменяемы, поэтому квалификатор mutable является избыточным. - person bavaza; 07.04.2011
comment
@bavaza: я почти уверен, что Хоакин знает, что итераторы постоянны, поскольку он является автором библиотеки Boost.MultiIndex. Вы попробовали его предложение или просто решили, что оно не сработает? Кажется, вы думаете, что mutable противоположно const, но это не так. Члены не изменяемы по умолчанию. - person interjay; 13.04.2011
comment
@Juaquin, Interjay: я попробовал mutable, и проблема решена. Спасибо. - person bavaza; 14.04.2011
comment
Проблема решена, но это mutable не очень плохой способ программирования на С++! - person Gabriel; 26.07.2013
comment
@bavaza члены класса/структуры по умолчанию изменяемы - это неверно. члены класса/структуры по умолчанию неконстантны, но не изменяемы. - person quant; 09.02.2015