在C++中迭代std :: set <std :: string>时出现分段错误

nik*_*hil 1 c++ iterator set segmentation-fault

我的代码的这部分(对于这个项目)给了我一个分段错误.源代码可在此处获得.

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;
  }
}
Run Code Online (Sandbox Code Playgroud)

这是我运行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
Run Code Online (Sandbox Code Playgroud)

我正在尝试迭代一个集合并执行一些操作.如果需要,我可以提供更多代码.如果有人能引导我到一个可以学习理解这些段错误的地方,我也会喜欢它.我对他们了解不多,遇到这些时我会感到恐慌.

这是System类的operator +.

void System::operator+(string pname)
{
  installed_packages.insert(pname);
  log.push_back("Added " + pname);
}
Run Code Online (Sandbox Code Playgroud)

我知道设计不是最好的,但我正在尝试实现该项目的清单项目,该项目涵盖了面向对象编程的各个领域.清单也可以在github上找到.

我试图通过调试器运行代码,printng out*sit.它可以工作一段时间然后崩溃.我不太了解gdb.

Hos*_*ork 5

StackOverflow有一些"什么是分段错误?" 风格问答:

什么是分段错误?

理想情况下,您在具有调试器的环境中工作,并且能够逐行执行代码或放置断点.这可以帮助您隔离崩溃周围的情况.你已经在堆栈跟踪中有一个行号 - 我们假设它是一个吸烟枪:

cout<<*sit<<endl;
Run Code Online (Sandbox Code Playgroud)

但是,逐步调试一个调试器可以回答这样的问题:第一次是否在循环中发生这种情况......如果没有,那么就在哪个元素上.


更新:看看你在GitHub上的代码片段(不包括上面的代码),我看到它ConcretePackage::getDependencies()按值而不是通过引用返回一个set .这意味着每次调用该成员时,都会获得该集的新副本.来自不同容器的迭代器不应相互比较,即使它们是相同的类型:

比较来自不同容器的迭代器

要解决这个问题,您可以更改:

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

...到:

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

...或者您可以更改getDependencies的定义以返回引用:

set<string>& ConcretePackage::getDependencies() {
    return dependencies;
}
Run Code Online (Sandbox Code Playgroud)

研究以一种方式与另一种方式进行的原因是留给学生的练习.:P


还有一些说明:

  • 对于要使用迭代器的集合类,您不需要针对零大小的特殊情况测试.如果一个集合不包含任何元素,那么该.begin()集合将返回一个等于的集合.end().你上面的循环处理这种情况很好,并会立即退出.

  • 明确调用operator+代码而不用返回值做任何事情表明你可能有某种副作用.很少有人希望表达式a = b + c能够改变bc......而且单行代码b->operator+(c);表明你正在做某种事情.虽然技术上可行,但我会避免它.请参见此处的第2点: 运算符重载

  • 当您发布代码示例时,请尝试使其保持可读性,并且不需要显示大量滚动条.如果您在预览中注意到它正在放置一个长水平滚动条,则会打破排队.不要为每个支撑使用单独的线,而是将它们放在与条件相同的线上.(无论您在代码库中使用什么约定,在网上寻求技术帮助时,更简洁.)

(还提供上下文.如果你没有说它的作业和你自己的设计,那么像我这样的人会去谷歌搜索你想要使用的是什么类型的包管理器.幸运的是我找到了你的程序员.stackexchange.com发布...)