2015-06-14 4 views
2

Я получаю segfault на MacOSX («Ошибка сегментации: 11», в gdb «Сигнал программы SIGSEGV, ошибка сегментации»), появляющийся в деструкторе в котором контейнер зацикливается с итератором и память удалена. Я пробовал с clang ++, g ++ (обе части LLVM) и homebrew g ++. Выдаёт ошибку сегментации появляется, когда итератор увеличивается в первый раз, с сообщением GDB (будучи скомпилирован с лязгом ++)C++ segfault на одной платформе (MacOSX), но не другой (linux)

"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 я также получить предупреждение о том, «предупреждение: не удалось открыть OSO архивный файл ».

На кластерном узле linux, с gcc 4.8.1, я не получаю segfault. Любые идеи, что может быть неправильным, и как я могу избежать segfault на моем mac (желательно с clang)? Я действительно мало знаю о компиляторах и тому подобных.


EDIT:


Я думаю, что я нашел эту проблему, однако я хотел бы понять, почему это до сих пор работает на одной платформе, но не другой. Вот минимальный пример:

класс Слово:

#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 

Основная программа:

#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() странной, потому что карта изменяется во время ее повторения (что-то вроде двойного удаления, я полагаю). Segfault исчезает либо путем полного удаления DeleteAll, либо удаления деструктора Word.

Так что мне все еще интересно, почему segfault не появляется на linux с g ++ из gcc 4.8.1. (Кроме того, я предполагаю, что не по теме, я задаюсь вопросом о самом программировании - то, что было бы правильным способом лечения удаление индекса стирания/памяти в этом коде?)


EDIT 2:


Я не думаю, что это дубликат Vector.erase(Iterator) causes bad memory access, потому что мой первоначальный вопрос был связан с тем, почему я получаю segfault на одной платформе, а не в другой. Возможно, другой вопрос объясняет segfault как таковой (не знаю, как обойти эту проблему ... возможно, удалить деструктор Word и удалить удаление из DeleteAll(), а не «удалить»? Но этот деструктор имеет смысл для меня, хотя .. .), но если это действительно ошибка в коде, почему GSC g ++ не подхвачен?

+5

Возможно, у вас [* неопределенное поведение *] (https://en.wikipedia.org/wiki/Undefined_behavior), но, не имея возможности увидеть соответствующий код, трудно сказать что-то более конкретное. Создайте [Минимальный, полный и проверенный пример] (http://stackoverflow.com/help/mcve) и покажите нам. –

+1

Вы удаляете объект, на который указывает итератор, а затем пытаетесь его увеличить? – Buddy

+1

Возможный дубликат [Vector.erase (Iterator) вызывает плохой доступ к памяти] (http://stackoverflow.com/questions/2943912/vector-eraseiterator-causes-bad-memory-access) –

ответ

1

Это проблема:

~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, которая стирает с карты , что вы Перебор. Это аннулирует ваш активный итератор, что приводит к неопределенному поведению.Потому что это UB, тот факт, что он работает на одной платформе, но не другой, - это просто удача (или ее отсутствие).

Чтобы исправить это, вы можете сделать копию index и перебрать ее, рассмотреть другой дизайн, который не изменяет индекс при его удалении, или использовать тот факт, что erase возвращает следующий действительный итератор, чтобы сделать (что означает подъем erase в DeleteAll).

Смежные вопросы