我的代码的这部分(this project)给了我一个分段错误。源代码可用here。
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和backtrace时出现错误。
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类的operator +。
void System::operator+(string pname)
{
installed_packages.insert(pname);
log.push_back("Added " + pname);
}
我知道设计不是最好的,但我正在尝试实现该项目的清单项目,该项目涵盖了面向对象编程的各个方面。清单也可以在github上找到。
我试图通过调试器运行代码,打印出来* sit。它可以工作一段时间然后崩溃。我不太了解gdb。
答案 0 :(得分:5)
StackOverflow有一些“什么是分段错误?”风格Q&amp; A:
理想情况下,您在具有调试器的环境中工作,并且能够逐行执行代码或放置断点。这可以帮助您隔离崩溃周围的情况。你已经在堆栈跟踪中有一个行号 - 我们假设这是一个吸烟枪:
cout<<*sit<<endl;
但是通过调试器逐步完成可以回答这样的问题,例如这是否是第一次发生在循环中......如果不是,那么在哪个元素上。
更新:看看你在GitHub上的代码片段(不包括上面的代码),我看到ConcretePackage::getDependencies()
正在返回一个的集合值而非按引用。这意味着每次调用该成员时,都会获得该集的新副本。来自不同容器的迭代器不应相互比较,即使它们是相同的类型:
comparing iterators from different containers
要解决此问题,您可以更改:
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点:Operator overloading
发布代码示例时,请尝试保持可读性,不需要显示很多滚动条。如果您在预览中注意到它正在放置一个较长的水平滚动条,则会中断对齐。不要为每个支撑使用单独的线,而是将它们放在与条件相同的线上。 (无论您在代码库中使用什么约定,在网上寻求技术帮助时,更简洁。)
(还提供上下文。如果你没有说它的作业和你自己的设计,那么像我这样的人会去谷歌搜索你想要使用什么类型的包管理器。幸运的是我找到了你的programmers.stackexchange.com发布...)