2013-10-04 2 views
0

У меня есть std::map, где я сохраняю указатель на класс. В конструкторе класса передаются несколько значений, поэтому переменные в классе имеют фактическое значение. Моя проблема заключается в том, что ключевое слово this создает ошибку сегментации, когда я вызываю функцию этого класса, которая использует одну из ранее определенных переменных. Это выглядит, как это в деталях (короткая версия):«this» ключевое слово вызывает ошибку сегментации

Command::Command(const char *name, commandHandler h) // commandHandler is a function pointer 
{ 
    this->name = name; 
    this->handler = h; 
} 

Command::execute(int cn, std::vector<char *> args) 
{ 
    if (this->handler != NULL) // "this" is according to gdb a pointer to a class Command at 0x0 
     (handler)(cn, args); 
} 

Карта находится в статическом классе, то элементы карты вставляются в статической функции.

Edit: В связи с комментариями и ответами (спасибо ребята): добавить указатель класса в функции registerCommands(), который в основном создает указатели с помощью Command *command_xxx = new Command("xxx", &(handler_func)); и помещает его в карту в статическом классе. Вызов поступает из другого метода в том же классе, что и функция map и registerCommands(). Указатель класса получается с использованием commands.find("xxx")->second;, который возвращает null -> null указатель.

+0

показать код вызова – Kal

+0

Исходя из контекста, точная проблема не может быть определена. На основе описания объект, по которому вы хотите вызвать функцию, теряется или вы вызываете забавный указатель (например, нулевой указатель) при вызове функции-члена. –

ответ

2

указатель класса получается с помощью commands.find("xxx")->second; который возвращает null -> null указатель.

А затем, когда вы делаете commands.find("xxx")->second->execute(...), вы получаете segfault. Здесь есть (по крайней мере) две вещи.

Один из них - ->execute(...), не проверяя, не найден ли найденный элемент. Вы вызываете неопределенное поведение, если найденный элемент имеет значение null. Что происходит с большинством систем, зависит от того, является ли виртуальная функция execute(). Если это виртуально, вы получите сообщение об ошибке segfault или bus перед вызовом. Если он не виртуальный, базовая машина точно знает, какую функцию вызывать. Segfault будет происходить внутри функции execute() при попытке доступа к элементу данных. Вы должны либо знать, что указатель не является нулевым или проверить, не до того, как отправить вызов объекта. Как только вы делаете ->execute(), это игра, так или иначе.

Другой проблемой является ->second. Что делать, если "xxx" нет на карте? Если это не так, commands.find("xxx") вернет commands.end(), и работа над этим будет неопределенным поведением. Все, что вам нужно сделать с конечным итератором, - это тест, который вы не ударили.

Это немного более подробно, но вы должны проверить эти угловые шкафы.Вы должны проверить, даже если после тщательного анализа вы знаете со 100% уверенностью в том, что ваш find всегда будет возвращать итератор в границах и что каждый итератор in-bounds имеет ненулевое отображаемое значение. Вы можете протестировать с помощью утверждений, и вы можете в конечном итоге отключить их, но вы должны всегда тестировать. Всегда.

+0

Похоже, что это не сохраняет указатель класса на карте. Благодарю. – user2610529

2

В основном это происходит, когда вы вызываете метод указателя, который установлен на NULL. Поскольку является скрытым параметром, который передается каждой функции-члену, GDB показывает его как NULL. Например:

Command *command = NULL; 
command->execute(...); 
2

У вас есть указатель на Command где-нибудь, но указатель 0. Этот указатель затем используется для вызова Command::execute, что означает, что функция-член вызывается с this == 0.

Хотя это не является стандартным конформным, вы можете скорее всего, попытается добавить код, чтобы поймать это и напечатать какую-то информацию, которая может помочь в отладке проблемы:

if(!this) print_backtrace(); 

или что-то подобное. (Для трассировки на Linux, см this answer я дал незадолго назад)

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