Увеличьте падение multi_index_container в режиме релиза - PullRequest
0 голосов
/ 20 мая 2010

У меня есть программа, которую я только что изменил, используя коллекцию boost :: multi_index_container. После того, как я сделал это и протестировал мой код в режиме отладки, я чувствовал себя довольно хорошо.

Однако затем я скомпилировал сборку релиза с набором NDEBUG, и код потерпел крах. Не сразу, но иногда в однопоточных тестах и ​​часто в многопоточных тестах.

Ошибки сегментации происходят глубоко внутри вставки наддува и функций поворота, связанных с обновлениями индекса, и происходят потому, что узел имеет нулевые левый и правый указатели.

Мой код выглядит примерно так:

struct Implementation {
    typedef std::pair<uint32_t, uint32_t> update_pair_type;
    struct watch {};
    struct update {};
    typedef boost::multi_index_container<
        update_pair_type,
        boost::multi_index::indexed_by<
            boost::multi_index::ordered_unique<
                boost::multi_index::tag<watch>,
                boost::multi_index::member<update_pair_type, uint32_t, &update_pair_type::first>
            >,   
            boost::multi_index::ordered_non_unique<
                boost::multi_index::tag<update>,
                boost::multi_index::member<update_pair_type, uint32_t, &update_pair_type::second>
            >    
        >    
    > update_map_type;
    typedef std::vector< update_pair_type > update_list_type;

    update_map_type update_map;
    update_map_type::iterator update_hint;

void register_update(uint32_t watch, uint32_t update);
void do_updates(uint32_t start, uint32_t end);
};

void Implementation::register_update(uint32_t watch, uint32_t update)
{
    update_pair_type new_pair( watch_offset, update_offset );
    update_hint = update_map.insert(update_hint, new_pair);
    if( update_hint->second != update_offset ) {
        bool replaced _unused_ = update_map.replace(update_hint, new_pair);
        assert(replaced);
    }
}

Ответы [ 2 ]

1 голос
/ 20 мая 2010

Я знал ответ, когда отправлял вопрос, но думал, что поделюсь этим для всеобщего наставления. Я не нашел ответов, когда сам гуглил, поэтому мне пришлось самому в этом разобраться.

Я вижу, как другие программисты легко попадают в ту же ловушку.

Проблема с update_hint в моем коде. Используется следующим register_update вызовом. Обычно это работает очень хорошо.

НО!

Использование подсказки вставки после вызова replace делает эту подсказку вставки недействительной! По какой-то причине он работает большую часть времени и всегда работает в режиме отладки. Boost, кажется, использует подсказку, не проверяемую в некоторых случаях при компиляции в режиме релиза, и это оказывается убийцей.

0 голосов
/ 10 июля 2014

Я думаю, что ваш ответ не верен. replace сохраняет действительность update_hint во всех случаях (см. документы ). Фактически, эта операция не реализована как стирание, за которым следует вставка (как предложено @Matthieu), но более умная (замена выполняется на месте).

Проверяя ваш код, легко доказать, что, если update_hint является действительным итератором при вызове register_update, он останется действительным после выполнения: insert всегда возвращает действительное значение ( и разыменованный) итератор, и replace не изменяет и не делает недействительным update_hint. Таким образом, единственная возможность состоит в том, что update_hint признан недействительным вне register_update. Вероятные причины:

  1. Элемент, на который указывает update_hint, стирается где-то еще в Implementation коде.
  2. Вы неправильно инициализируете update_hint действительным значением в Implementation время строительства.

НТН

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...