присвоение значения из вектора (общего указателя) общему указателю вызывает ошибку сегментации c ++

В моем коде есть vector <vector <vector <vector <std::tr1::shared_ptr<foo> > > > > с именем foosBoxes. Вложенный вектор играет роль имитации физического положения ящиков. У меня также есть цикл while, который вызывает ошибку сегментации:

vector<std::tr1::shared_ptr<foo> >::iterator fooit = foosBoxes[x][y][z].begin(); //x,y,z are valid integer
std::tr1::shared_ptr<foo> aFoo;
while (fooit != foosBoxes[x][y][z].end()){
  aFoo = *fooit; //this cause segmentation fault
  fooit++;
  //some stuff which does not have an effect on fooit;
}

Некоторые вещи, которые я пробовал:
1. Я пытался использовать aFoo = *fooit++, но это не сработало.
2. Ошибка сегментации возникает примерно после нескольких тысячных циклов, которые прошли нормально.
3. У меня есть попытался valgrind решить проблему, и valgrind выполнил этот шаг.
4. В цикле, в котором произошел сбой, я напечатал текущий счетчик до и после подозрительной строки. когда перед строкой я получаю 8 распечаток (размер вектора), а когда после - 7 распечаток.

Как я могу в этом разобраться?

Обновление:
я добавил цикл для запуска перед основным циклом:

int kkk = 1214
int c = 0;
while (c < foosBoxes[x][y][z].end()){
   aFoo = foosBoxes[x][y][z][c++];
   printf("%i\t, kkk);
   fflush(stdout);
}

Что дает те же результаты.

Обновление:
согласно GDB:

Программа получила сигнал SIGSEGV, Ошибка сегментации. 0x000000000043e400 в повороте (kkk = 1214) в /usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/tr1/boost_shared_ptr. h: 153 153 dispose ();

Я думаю, что подходящей функцией в boost_shared_ptr.h является

void
  release() // nothrow                                                                                                                      
  {
    if (__gnu_cxx::__exchange_and_add(&_M_use_count, -1) == 1)
      {
        dispose(); //this is line 153
#ifdef __GTHREADS
        _GLIBCXX_READ_MEM_BARRIER;
        _GLIBCXX_WRITE_MEM_BARRIER;
#endif
        if (__gnu_cxx::__exchange_and_add(&_M_weak_count, -1) == 1)
          destroy();
      }
  }

dispose() определяется в другом месте файла:

  // dispose() is called when _M_use_count drops to zero, to release                                                                        
  // the resources managed by *this.                                                                                                        
  virtual void
  dispose() = 0; // nothrow  

Может быть, причина в плохом управлении shared_ptr, и я должен вернуться к обычному указателю?

Обновление:
еще один тест с аналогичным результатом:

int kkk = 1214 int c = fooBoxes [x] [y] [z] .size (); в то время как (c> = 0) {aFoo = foosBoxes [x] [y] [z] [c--]; printf ("% i \ t, kkk); fflush (stdout);}

На этот раз программа вылетает на третьей итерации. Если проблема заключалась в неправильном распределении, тогда программа должна была дать сбой на первой итерации (в обратном направлении программа выйдет из строя на первой итерации).


person Yotam    schedule 17.08.2011    source источник
comment
Из того, что вы сказали, похоже, что какой-то код где-то еще вызывает неопределенное поведение. Вы пробовали запускать его с помощью valgrind или аналогичных инструментов для своей платформы?   -  person Flexo    schedule 17.08.2011
comment
@awoodland: да, я пробовал valgrind (номер 3 в списке вещей, которые я пробовал) проблема в том, что valgeind пережил этот шаг ...   -  person Yotam    schedule 17.08.2011
comment
Попробуйте включить всевозможные режимы отладки (с точки зрения компилятора и библиотеки) и постарайтесь сократить объем кода до минимума, чтобы изолировать ошибку.   -  person sellibitze    schedule 17.08.2011


Ответы (5)


Запустите свой код с помощью libstdc ++ в режиме отладки. Он проведет дополнительные проверки итераторов, контейнеров и алгоритмов и, надеюсь, поможет найти ошибку.

person ks1322    schedule 17.08.2011
comment
Как запустить libstdc ++? У меня на машине есть компиляторы gcc и g ++. - person Yotam; 17.08.2011
comment
Прочтите статью Использование режима отладки. Чтобы использовать режим отладки libstdc ++, скомпилируйте приложение с флагом компилятора -D_GLIBCXX_DEBUG и перезапустите код. Надеюсь, он выйдет из строя из-за недопустимого действия. - person ks1322; 17.08.2011
comment
libstdc ++ - это разделяемая библиотека, реализующая стандартную библиотеку C ++. Поставляется с компилятором g ++. - person ks1322; 17.08.2011
comment
Я пробовал это и получил ошибку попытка сравнить единичный итератор с итератором, прошедшим конец Теперь я пытаюсь найти причину этого (конкретная функция не печатается) - person Yotam; 17.08.2011
comment
Если он бросал (я думаю, что должен), вы можете работать под gdb и останавливаться на исключениях. Это должно остановить вас прямо в том месте, где обнаружена проблема. - person Tomek; 17.08.2011
comment
Как я могу проверить, допустимо ли значение (либо gdb, либо внутри кода)? Я подозреваю, что я убрал указатель из вектора, но конечный итератор не обновился ... - person Yotam; 17.08.2011
comment
Согласно сообщению об ошибке, вы сравниваете недопустимый итератор с итератором end. Единственное место, где это происходит, - while (fooit != foosBoxes[x][y][z].end()){. Итак, я предполагаю, что в какой-то момент итератор fooit станет недействительным. - person ks1322; 17.08.2011

//some stuff which does not have an effect on fooit;

Но влияет ли этот материал на foosBoxes [x] [y] [z]? В частности, он удаляет элементы или вызывает перемещение вектора? В таком случае fooit не может быть осмысленно сравнен с foosBoxes [x] [y] [z] .end ().

Кроме того, что происходит с aFoo в цикле? Если он получает недопустимое значение, последующее присвоение ему приведет к неопределенному поведению.

Попробуйте удалить some stuff из цикла. Если это сработает, материал содержит ошибку. Если цикл по-прежнему не удается, причиной должно быть недопустимое значение в fooxBoxes [], прежде чем вы войдете в цикл.

У меня нет опыта работы с ValGrind. Но я использовал похожие продукты. Убедитесь, что вы настроили ValGrind на самые строгие настройки. Это может сделать его использование очень медленным, но, надеюсь, обнаружит ошибку.

person Leo    schedule 17.08.2011
comment
Мой опыт работы с valgrind почти так же ограничен, как и ваш ... fooBoxes не изменяется во время цикла, но может быть изменен в другом месте и имеет эффект. Второй сейчас проверяю. - person Yotam; 17.08.2011
comment
Хорошо, я добавил цикл для запуска перед основным циклом, пожалуйста, прочтите мое обновление вопроса - person Yotam; 17.08.2011
comment
Я должен согласиться - мне кажется, что вы заставляете этот вектор перераспределять и блокировать итераторы. - person Puppy; 17.08.2011
comment
@DeadMG: Я попытался выполнить итерацию в другом направлении, и программа не сработала на первой итерации. Прочтите, пожалуйста, мое дополнение к вопросу. Я также перебрал все foos (отдельный вектор), и там ничего не сломалось. Вы случайно не знаете, как я могу распечатать содержимое вектора int gdb? - person Yotam; 17.08.2011

Вы код, поскольку он выглядит нормально, единственное, что я могу думать, это то, что x y z действительны? operator[] не проверяет границы ...

person Nim    schedule 17.08.2011
comment
Я бы проверил это, используя at(), а не оператор ... может показаться ... - person Nim; 17.08.2011

Я пришел к выводу, что проблема заключалась в использовании vector неправильно, так как я обновляю его через код. Я не знаю, как работает управление памятью в c++, но я считаю, что произошло какое-то перекрытие между двумя векторами. Я перешел на set и теперь все работает

person Yotam    schedule 19.08.2011

Чтобы работать с элементом foosBoxes[x][y][z], вы также можете попробовать:

while (fooit != foosBoxes[x][y][z].end()){
      vector<std::tr1::shared_ptr<foo> > *aFoo = *fooit; 
       fooit++;
      //To use the object 
     // use it as   aFoo->method()  
 }

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

person Shubhendu Sinha    schedule 17.08.2011