ошибка сегментации при удалении карты с ключом struct - PullRequest
2 голосов
/ 29 февраля 2012

В моем коде есть структура, которую я использую в качестве ключа карты:

struct index{
  int x;
  int y;
  int z;
  bool operator<(const index &b){
    bool out = true;
    if ( x == b.x ){
      if ( y == b.y ){
        out = z < b.z;
      } else out = y < b.y;
    } else out = x < b.x;
    return out;
  }
};

и карта, которую я использую:

map<index,set<std::pair<int, int> > > tBoxes;

Когда программа завершает свою работу, и я пытаюсь освободить память, я получаю ошибку сегментации, когда программа пытается удалить карту. Используя GDB я получаю:

#0  std::_Rb_tree<membrane::index, std::pair<membrane::index const, std::set<std::pair<int, int>, std::less<std::pair<int, int> >, std::allocator<std::pair<int, int> > > >, std::_Select1st<std::pair<membrane::index const, std::set<std::pair<int, int>, std::less<std::pair<int, int> >, std::allocator<std::pair<int, int> > > > >, std::less<membrane::index>, std::allocator<std::pair<membrane::index const, std::set<std::pair<int, int>, std::less<std::pair<int, int> >, std::allocator<std::pair<int, int> > > > > >::_M_erase (this=0x63b900, 
    __x=0x404057eb274ede6c)
    at /usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_tree.h:1264
#1  0x000000000041ed2f in std::_Rb_tree<membrane::index, std::pair<membrane::index const, std::set<std::pair<int, int>, std::less<std::pair<int, int> >, std::allocator<std::pair<int, int> > > >, std::_Select1st<std::pair<membrane::index const, std::set<std::pair<int, int>, std::less<std::pair<int, int> >, std::allocator<std::pair<int, int> > > > >, std::less<membrane::index>, std::allocator<std::pair<membrane::index const, std::set<std::pair<int, int>, std::less<std::pair<int, int> >, std::allocator<std::pair<int, int> > > > > >::_M_erase (
    this=0x63b900, __x=0x7d31110)
    at /usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_tree.h:1264
#2  0x000000000041ed2f in std::_Rb_tree<membrane::index, std::pair<membrane::index const, std::set<std::pair<int, int>, std::less<std::pair<int, int> >, std::allocator<std::pair<int, int> > > >, std::_Select1st<std::pair<membrane::index const, std::set<std::pair<int, int>, std::less<std::pair<int, int> >, std::allocator<std::pair<int, int> > > > >, std::less<membrane::index>, std::allocator<std::pair<membrane::index const, std::set<std::pair<int, int>, std::less<std::pair<int, int> >, std::allocator<std::pair<int, int> > > > > >::_M_erase (
    this=0x63b900, __x=0x7d30e30)
    at /usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_tree.h:1264
#3  0x000000000041ed2f in std::_Rb_tree<membrane::index, std::pair<membrane::index const, std::set<std::pair<int, int>, std::less<std::pair<int, int> >, std::allocator<std::pair<int, int> > > >, std::_Select1st<std::pair<membrane::index const, std::set<std::pair<int, int>, std::less<std::pair<int, int> >, std::allocator<std::pair<int, int> > > > >, std::less<membrane::index>, std::allocator<std::pair<membrane::index const, std::set<std::pair<int, int>, std::less<std::pair<int, int> >, std::allocator<std::pair<int, int> > > > > >::_M_erase (
    this=0x63b900, __x=0x7d30b50)
    at /usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_tree.h:1264
#4  0x000000000041ed2f in std::_Rb_tree<membrane::index, std::pair<membrane::index const, std::set<std::pair<int, int>, std::less<std::pair<int, int> >, std::allocator<std::pair<int, int> > > >, std::_Select1st<std::pair<membrane::index const, std::set<std::pair<int, int>, std::less<std::pair<int, int> >, std::allocator<std::pair<int, int> > > > >, std::less<membrane::index>, std::allocator<std::pair<membrane::index const, std::set<std::pair<int, int>, std::less<std::pair<int, int> >, std::allocator<std::pair<int, int> > > > > >::_M_erase (
    this=0x63b900, __x=0x7d272c0)
    at /usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_tree.h:1264
#5  0x0000000000418237 in clear (this=0x63b3e0, 
    __in_chrg=<value optimized out>)
    at /usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_tree.h:692
#6  clear (this=0x63b3e0, __in_chrg=<value optimized out>)
    at /usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_map.h:501
#7  membrane::~membrane (this=0x63b3e0, __in_chrg=<value optimized out>)
    at memMC.cpp:135
#8  0x0000000000421658 in __tcf_5 () at main.cpp:7
#9  0x000000378ea334f5 in exit () from /lib64/libc.so.6
#10 0x000000378ea1d99b in __libc_start_main () from /lib64/libc.so.6
#11 0x0000000000402309 in _start ()

И используя valgrind (работает $valgrind -v --track-origins=yes --leak-check=yes --tool=massig --tool=memcheck --read-var-info=yes --log-file=error.txt ./mem), я получаю:

==2561==     in use at exit: 0 bytes in 0 blocks
==2561==   total heap usage: 3,346,323 allocs, 3,346,323 frees, 98,851,279 bytes allocated
==2561== 
==2561== All heap blocks were freed -- no leaks are possible
==2561== 
==2561== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 4 from 4)
--2561-- 
--2561-- used_suppression:      4 dl-hack3
==2561== 
==2561== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 4 from 4)

Что раздражает, поскольку ничего мне не говорит.

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

while (tBoxes.size() > 0){
   printf ("%i  ", (*tBoxes.begin()).first.x);
   printf ("%i  ", (*tBoxes.begin()).first.y);
   printf ("%i\n", (*tBoxes.begin()).first.z);
   while ((*tBoxes.begin()).second.size() > 0){
     printf ("a\n");      
     tgBit1 = (*tBoxes.begin()).second.begin();
     (*tBoxes.begin()).second.erase(tgBit1);
     printf ("b\n");
   }
   tBoxes.erase(tBoxes.begin());
 }
 tBoxes.clear();
 tNextBoxes.clear();

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

Почему это происходит и есть ли способ очистить карту, кроме использования clear ()?

Edit:

Я нашел ошибку. Один из векторов, который я использовал, был неправильно настроен и имел размер 0. Тем не менее, я все еще обращался к элементу в этом векторе.

Вектор имеет значения double, и я использую это значение после деления на размер поля и округления результата вниз, чтобы определить tBox для добавления пары. Я предполагаю, что получил недопустимое значение для использования в index. Остается вопрос, почему программа не сломалась, когда я попытался получить доступ к этому элементу ...?

1 Ответ

2 голосов
/ 01 марта 2012

Я предполагаю, что существует какое-то повреждение кучи / стека, происходящее где-то еще в вашей программе, которое проявляется только тогда, когда ваша карта пытается получить доступ к неверному указателю / итератору.Посмотрите на последний удаленный итератор (0x404057eb274ede6c), который выглядит подозрительно по сравнению с предыдущими значениями итератора (0x7d31110).

Почему Valgrind не обнаруживает это повреждение?Я не очень знаком с инструментом, но этот вопрос на SE указывает на еще один случай, когда Valgrind не обнаруживает «очевидное» плохое поведение, а также предлагает что-то еще, чтобы помочь его обнаружить.

Я бы попытался уменьшить количество сбоев до как можно меньшего количества кода.Создайте небольшой тестовый пример в другом проекте и посмотрите, происходит ли сбой.Запустите в режиме отладки и / или с дополнительными проверками памяти, чтобы выяснить, можно ли обнаружить повреждение памяти (при условии, что это так).

Обновление для редактирования:

Предполагая, что вы используете std::vector::operator[], этот метод не выполняет проверку границ и, к счастью, позволит вам получить доступ к элементам, которые не существуют.Я считаю, что это определено как неопределенное поведение, и, к сожалению, одним из возможных результатов является то, что ничего не происходит.

Если вы хотите или должны иметь границы, проверяя их, используйте std::vector::at(), см. этот вопрос для нескольких деталей.Обычно вы используете [], только когда знаете, что используемый индекс находится в границах, как в итерационном цикле или когда индекс проверяется вручную.

...