我在MacOSX(Segmentation fault:11,在gdb“程序接收到的信号SIGSEGV,Segmentation fault”)中收到一个段错误,出现在析构函数中,在这个析构函数中,一个迭代器和内存被删除。 我已经尝试过clang ++,g ++(LLVM的一部分)和homebrew g ++。 迭代器第一次增加时会出现segfault,gdb消息(用clang ++编译)
"0x000000010001196d in std::__1::__tree_node_base<void*>* std::__1::__tree_next<std::__1::__tree_node_base<void*>*>(std::__1::__tree_node_base<void*>*) ()"
当在gdb中启动程序的时候,我也会收到警告,提示“warning:Could not open OSO archive file”。
在一个集群linux节点上,用gcc 4.8.1,我没有得到一个段错误。 任何想法可能是错误的,以及如何我可以避免在我的Mac(最好与铛)的段错误? 我真的不太了解编译器等。
编辑:
我想我发现了这个问题,但是我想了解为什么这个工作在一个平台上而不是另一个平台上。 这是一个最小的例子:
class级Word:
#ifndef WORD_H #define WORD_H #include <string> #include <map> class Word { public: /*** Constructor ***/ Word(std::string w) : m_word(w) { // Add word to index map, if it's not already in there std::map<std::string, Word*>::iterator it = index.find(w); if (it == index.end()) { index[w] = this; } } ~Word() { index.erase(m_word); } // Remove from index static void DeleteAll() { // Clear index, delete all allocated memory for (std::map<std::string, Word*>::const_iterator it = index.begin(); it != index.end(); ++it) { delete it->second; } } private: std::string m_word; static std::map<std::string, Word*> index; // Index holding all words initialized }; #endif
WordHandler类:
#ifndef _WORDHANDLER_H_ #define _WORDHANDLER_H_ #include <string> #include "Word.h" class WordHandler { WordHandler() {} ~WordHandler() { Word::DeleteAll(); } // clear memory void WordHandler::NewWord(const std::string word) { Word* w = new Word(word); } }; #endif
主要scheme:
#include <iostream> #include "WordHandler.h" int main () { std::cout << "Welcome to the WordHandler. " << std::endl; WordHandler wh; wh.NewWord("hallon"); wh.NewWord("karl"); std::cout << "About to exit WordHandler after having added two new words " << std::endl; return 0; }
所以在程序退出的时候出现段错误,当析构函数〜WordHandler被调用时。 我发现的原因是Word的析构函数:从映射中删除了Word对象,这使得DeleteAll()函数变得怪异,因为在迭代过程中地图被修改了(某种双重删除我想)。 通过完全删除DeleteAll或删除Word析构函数,segfault消失。
所以我仍然想知道为什么segfault不会出现在Linux上与gcc 4.8.1 g ++。 (另外,我猜的主题,我想知道编程本身 – 在这个代码中删除索引擦除/内存删除的正确方法是什么?)
编辑2:
我不认为这是Vector.erase(迭代器)导致不良内存访问的重复,因为我原来的问题是为什么我在一个平台上得到一个段错误,而不是另一个。 这可能是另一个问题解释segfault本身(不知道如何解决这个问题…也许删除Word析构函数,并从DeleteAll()而不是“delete”调用擦除?但那个析构函数虽然对我来说是有道理的.. 。),但如果它真的是代码中的错误,为什么不被gcc g ++拾取?
这是个问题:
~Word() { index.erase(m_word); } // Remove from index static void DeleteAll() { // Clear index, delete all allocated memory for (std::map<std::string, Word*>::const_iterator it = index.begin(); it != index.end(); ++it) { delete it->second; } }
delete it->second
调用~Word
从地图上擦除的~Word
,你正在迭代 。 这使您的活动迭代器失效,导致未定义的行为。 因为它是UB,所以它在一个平台上工作而不是另一个平台的事实基本上是运气(或缺乏)。
要解决这个问题,你可以创建一个index
的副本并迭代它,考虑一个不同的设计,在删除索引时不会改变索引,或者使用erase
返回下一个有效的迭代器来使循环安全这意味着将erase
提升到DeleteAll
)。