在C++中迭代 std::set<std::string> 时出现分段错误
Segmentation fault while iterating a std::set<std::string> in C++
我的这部分代码(对于这个项目)给了我一个分段错误。源代码在这里。
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上找到。
我已经尝试通过调试器运行代码,打印出*sit。它可以工作一段时间,然后崩溃。我对gdb了解不多
StackOverflow有几个"什么是分段错误?"风格的问题& a:
什么是分段错误?
理想情况下,您在一个有调试器的环境中工作,并且能够逐行检查代码,或者设置断点。这可以帮助您隔离您的事故周围的环境。在堆栈跟踪中已经有了行号——我们假设它指向一个确凿的证据:
cout<<*sit<<endl;
但是使用调试器可以回答诸如是否在第一次通过循环时发生这种情况之类的问题…
UPDATE:看看你在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点:操作符重载当你发布代码样本时,尽量保持它们的可读性,而不需要很多滚动条来显示。如果你在预览中注意到它放了一个很长的水平滚动条,就把线条分开。不要为每个大括号使用单独的行,而是将它们放在与条件相同的行上。(不管你在代码库中使用什么约定,在在线请求技术帮助时越简短越好。)
(也提供上下文。如果您不说这是您自己的作业和设计,那么像我这样的人就会去google搜索,试图弄清楚您使用的是哪种包管理器。幸运的是,我找到了你的programmers.stackexchange.com post…)
- 使用std::source_location报告错误的最佳实践
- std::is_base_of表示ctor编译错误
- 多个文件的内存分配错误"在抛出 'std :: bad_alloc' what (): std :: bad_alloc 的实例后终止调用" [C++]
- 程序崩溃并显示"std::out_of_range"错误
- 在c++中尝试对对象数组进行排序时,出现std:bad_alloc错误
- 我收到以下错误:抛出'std::bad_alloc'实例后终止调用
- 尝试使用 std::vector<std::thread时出现静态断言失败错误>
- 错误 C2679:二进制"<<":未找到采用类型 'std::string_view' 的右侧操作数的运算符(或者没有可接受的转换)
- 为什么 std::绑定错误参数可以成功?
- std::cout输出int时出现编译错误
- 使用静态库与 std::jthread (g++-10) 的分段错误
- std::unordered_map 类型对象声明期间出现"field has incomplete type"错误
- 在缺少函数重载时抛出异常,并带有 std::variant 而不是编译时错误
- 使用 memcpy() 复制到 std::chrono::milliseconds 会给出错误 -Werror=clas
- 显式 std::exception_ptr 转换为 bool 不存在.VS2010 错误?
- "random_shuffle":不是"std"错误的成员
- VC++ 2010 "array is not a member of std"错误
- 开发C++ "to_string is not a member of std"错误
- STD未来异常-已检索,STD错误
- 交叉编译c++的树莓派std错误