2013-11-02 1 views
1

Я занимаюсь практикой кодирования на C++ в Visual Studio и продолжаю показывать эту проблему как заголовок. Я знаю, где проблема, но я не понимаю, почему это происходит и как ее решить. Пожалуйста, помогите мне с этим.нарушение доступа к чтению местоположение 0x000000004

class_templete.h

typedef std::string QuestionName; 
class ClassTemplete 
{ 
public: 
    ClassTemplete(Question iQuestionName); 
private 
    static std::map<QuestionName,ClassTemplete *> questionName_questionPointer_map_; 
} 

class_templete.cpp

map<QuestionName, ClassTemplete *> ClassTemplete::questionName_questionPointer_map_; 

ClassTemplete::ClassTemplete(QuestionName iQuestionName) 
{ 
    ClassTemplete::questionName_questionPointer_map_[iQuestionName] = this; 
} 

chapter1_question1.h

class C1Q1 : public ClassTemplete 
{ 
public: 
    C1Q1(QuestionName iQuestionName) : ClassTemplete(iQuestionName) {}; 
private: 
    static QuestionName question_name_; 
    static C1Q1 question_instance_; 
} 

chapter1_question1.cpp

QuestionName C1Q1::question_name_ = "C1Q1"; 
C1Q1 C1Q1::question_instance_(C1Q1::question_name_); 

я обнаружил, что проблема происходит в этом месте, когда я запускаю программу:

ClassTemplete::questionName_questionPointer_map_[iQuestionName] = this; 

Однако, я не могу объяснить, почему это происходит.

Пожалуйста, не стесняйтесь обращаться ко мне, если требуется дополнительная информация.

С наилучшими пожеланиями,

Yi Ji

+1

Похоже, что 'ClassTemplete :: questionName_questionPointer_map_' не инициализирован или инициализирован для NULL и индексирования массивов на этой недопустимой карте, вы пытаетесь сохранить что-то в ** 0x000 ... 4 ** –

+0

Вы пытались разыменовать нуль указатель. –

+0

На самом деле, чем больше я думаю об этом, это звучит как проблема инициализации на одном элементе, определенном в другой единицы перевода (class_templete.cpp).Это не правильный способ использования Singleton, методы доступа, которые завершают их, - это путь. –

ответ

5

Где QuestionName C1Q1:::question_name_ расположен относительно ClassTemplate::questionName_questionPointer_map_? Кажется, что они представляют собой переменные со статической продолжительностью хранения, т. Е. Они создаются до запуска main(). Однако компилятор/компоновщик C++ упорядочивает построение таких глобальных объектов только с одной единицей перевода (в этом случае объекты строятся сверху вниз), а не между единицами перевода (в этом случае объекты строятся в случайном порядке).

У вас проблема, как будто ClassTemplate::questionName_questionPointer_map будет построен после C1Q1::question_name_. То есть, когда строится C1Q1::question_name_, к объекту, который еще не построен, обращается к нему.

Традиционное исправление, чтобы сделать static объект другие объекты зависят от не объекта, а функция с локальным static переменной, к которой возвращается ссылка:

std::map<QuestionName,ClassTemplete *>& 
ClassTemplete::questionName_questionPointer_map_() { 
    static std::map<QuestionName,ClassTemplete *> rc; 
    return rc; 
} 

(обратите внимание, что эта конструкция не поточно-безопасный, если вы не используете C++ 11, он - это поточно-безопасный при использовании C++ 11).

+0

+1 и я хотел бы добавить в другое время на время, чтобы его рассеять. Как всегда, отличная работа, сэр. – WhozCraig

+0

@WhozCraig: Спасибо. Я думаю, я видел эту точную проблему достаточно часто, т. Е. Мне просто нужно было подтвердить соответствующие знаки (глобальные объекты в зависимости друг от друга). –

+0

@ DietmarKühl Спасибо, что ваше решение работает, когда я возвращаю ссылку на локальную статическую переменную. Тем не менее, я блуждаю, если в этом случае есть решение использовать статическую переменную questionName_questionPointer_map_ класса ClassTemplate. Если я использую локальную статическую переменную, то я определил ее раньше, чем бесполезно. :) – jiyi

0

Вы должны использовать std::map::insert, вы не можете сделать ClassTemplete::questionName_questionPointer_map_[iQuestionName] = this; при вставке нового ключа в карте.

Этот код должен работать:

ClassTemplete::questionName_questionPointer_map_.insert(std::make_pair(iQuestionName, this)); 

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

  • Нет связанных вопросов^_^