0

我有一个std::map保存指向类的指针的地方。在类的构造函数中传递了几个值,因此类中的变量具有实际值。我的问题是,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);
}

地图在静态类中,地图元素插入到静态函数中。

编辑:由于评论和答案(谢谢大家):我在函数 registerCommands() 中添加指向类的指针,该函数基本上使用创建指针Command *command_xxx = new Command("xxx", &(handler_func));并将其放入静态类的映射中。该调用来自与 map 和 registerCommands() 函数相同的类中的另一个方法。使用commands.find("xxx")->second;返回 null -> null 指针来获得类指针。

4

3 回答 3

2

使用commands.find("xxx")->second;获得类指针 它返回 null -> 空指针。

然后当你这样做时,你commands.find("xxx")->second->execute(...)会得到一个段错误。这里(至少)有两件事是错误的。

一种是->execute(...)不检查找到的项目是否为非空。如果找到的项目为空,您将调用未定义的行为。大多数系统会发生什么取决于是否execute()是虚拟功能。如果它是虚拟的,您将在调用之前收到段错误或总线错误。如果它是非虚拟的,则底层机器确切地知道要调用哪个函数。execute()当您尝试访问数据成员时,将在函数内部发生段错误。您应该知道指针不为空,或者在调度对象调用之前检查它是否为空。一旦你这样做->execute(),游戏就结束了,一种或另一种方式。

另一个问题是->second. 如果"xxx"不在地图上怎么办?如果不是,commands.find("xxx")将返回commands.end(),并且对其进行操作是未定义的行为。你应该对 end 迭代器做的就是测试你没有击中它。

它有点冗长,但你应该测试那些极端情况。即使经过艰苦的分析,您也应该测试 100% 确信您find将始终返回一个 in-bounds 迭代器并且每个 in-bounds 迭代器都有一个非空映射值。您可以通过断言进行测试,并且最终可以将其关闭,但您应该始终进行测试。总是。

于 2013-10-04T22:44:14.977 回答
2

这主要发生在您调用设置为 的指针上的方法时NULL。由于this是传递给每个成员函数的隐藏参数,因此 GDB 将其显示为NULL. 例如:

Command *command = NULL;
command->execute(...);
于 2013-10-04T22:10:19.540 回答
2

你有一个指向Command某个地方的指针,但指针是0. 然后用这个指针来调用Command::execute,这意味着成员函数是用 来调用的this == 0

虽然它不符合标准,但您很可能尝试添加代码来捕获它并打印一些可能有助于调试问题的信息:

if(!this) print_backtrace();

或类似的东西。(有关 Linux 的回溯,请参阅我不久前给出的这个答案)

于 2013-10-04T22:10:30.497 回答