Ошибка сегментации при итерации std :: set <std :: string> в C ++ - PullRequest
1 голос
/ 29 ноября 2011

Эта часть моего кода (для этого проекта ) дает мне ошибку сегментации. Исходный код доступен здесь .

void PackageManager::install_package(string pname)
{
  if(repository->exists_package(pname)) {
    Package *pkg;
    ConcretePackage *cpkg;
    MetaPackage *mpkg;
    if(repository->is_virtual(pname)) {
      //code for dealing with meta packages
      mpkg = new MetaPackage(pname);
      pkg = mpkg;
      system->operator+(pname);
    } else {
      //code for dealing with concrete packages
      cpkg = new ConcretePackage(pname);
      pkg = cpkg;
      system->operator+(pname);
      if( cpkg->getDependencies().size() > 0) {
        for(set<string>::iterator sit = pkg->getDependencies().begin();
            sit!=pkg->getDependencies().end(); ++sit) {
          cout<<*sit<<endl;
          system->operator+(*sit);
        }
      }
    }
  } else {
    cout<<"Invalid Package Name"<<endl;
  }
}

Вот ошибка при запуске gdb, а также обратная трассировка.

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7b6db03 in std::basic_ostream<char, std::char_traits<char> >& std::operator<< <char, std::char_traits<char>, std::allocator<char> >(std::basic_ostream<char, std::char_traits<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) ()
   from /usr/lib/libstdc++.so.6
(gdb) backtrace
#0  0x00007ffff7b6db03 in std::basic_ostream<char, std::char_traits<char> >& std::operator<< <char, std::char_traits<char>, std::allocator<char> >(std::basic_ostream<char, std::char_traits<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) ()
   from /usr/lib/libstdc++.so.6
#1  0x00000000004052e8 in PackageManager::install_package (this=0x7fffffffe280, pname=...) at packagemanager.cpp:39
#2  0x000000000040575a in main () at packagemanager.cpp:79

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

Это оператор + для класса System.

void System::operator+(string pname)
{
  installed_packages.insert(pname);
  log.push_back("Added " + pname);
}

Я знаю, что дизайн не лучший, но я пытаюсь реализовать элементы контрольного списка для этого проекта, который охватывает различные области объектно-ориентированного программирования. Контрольный список также доступен на github.

Я попытался запустить код через отладчик, printng out * sit. Это работает некоторое время, а затем вылетает. Я не слишком много знаю о GDB.

1 Ответ

5 голосов
/ 29 ноября 2011

StackOverflow имеет несколько «Что такое ошибка сегментации?»Стиль Q & A:

Что такое ошибка сегментации?

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

cout<<*sit<<endl;

Но если пройти через отладчик, можно ответить на вопросы, например, произойдет ли это в первый раз в цикле... а если нет, то по какому элементу.


ОБНОВЛЕНИЕ : Рассматривая фрагменты этого кода на GitHub (который не включает приведенный выше код),Я вижу, что ConcretePackage::getDependencies() возвращает набор по значению , а не по ссылке .Это означает, что каждый раз, когда вы звоните участнику, вы получаете новую копию набора.Итераторы из разных контейнеров не должны сравниваться друг с другом, даже если они одного типа:

сравнение итераторов из разных контейнеров

Для решения этой проблемы вы можете изменить:

for(set<string>::iterator sit = pkg->getDependencies().begin();
        sit!=pkg->getDependencies().end(); ++sit) { ... }

... в:

set<string> deps = pkg->getDependencies();
for(set<string>::iterator sit = deps.begin(); sit!=deps.end(); ++sit) { ... }

... или вы можете изменить определение getDependencies для возврата ссылки:

set<string>& ConcretePackage::getDependencies() {
    return dependencies;
}

ОбучениеПричины сделать это так или иначе оставлены ученику в качестве упражнения.: P


Еще несколько замечаний:

  • Вам не нужен специальный случай теста для нулевого размера для классов коллекции, которые вы собираетесь использоватьитераторы с.Если набор не содержит элементов, то .begin() этого набора вернет итератор, равный .end().Вышеописанный цикл прекрасно обрабатывает этот случай и немедленно завершается.

  • Явный вызов operator+ в вашем коде без каких-либо действий с возвращаемым значением предполагает, что у вас, вероятно, есть какая-то побочнаяэффект.Мало кто ожидает, что выражения типа a = b + c изменятся b или c ... и одна строка кода, например b->operator+(c);, предполагает, что вы делаете что-то в этом роде.Хотя технически это возможно, я бы избежал этого.См. Пункт № 2 здесь: Перегрузка оператора

  • Когда вы публикуете примеры кода, старайтесь, чтобы они были читабельными и не нуждались в большом количестве полос прокрутки для отображения.Разбейте линии, если вы заметили в предварительном просмотре, что в нем размещена длинная горизонтальная полоса прокрутки.Вместо использования отдельных строк для каждой фигурной скобки, поместите их в те же строки, что и условие.(Независимо от того, какое соглашение вы используете в своей кодовой базе, чем короче, тем лучше при обращении за технической помощью в Интернете.)

(Также предоставьте контекст. Если вы не говорите, что этодомашнее задание и собственный дизайн, тогда люди, подобные мне, отправятся на поиски и выяснят, какой менеджер пакетов вы используете. К счастью, я нашел ваш пост programmers.stackexchange.com ...)

...