3

我遇到了一个我不明白的段错误。我正在使用 Wt 库并用信号做一些花哨的事情(我只提到它是因为它使我能够尝试调试它)。

我从一个向量中获取一个指向我的一个小部件的指针,并试图在它指向的对象上调用一个方法。Gdb 显示指针解析,如果我检查它指向的对象,它正是我需要修改的对象。在这种情况下,小部件正在向自己广播,因此它同时注册为广播者和侦听器;因此,我还能够验证“广播”指针和“侦听器”指针访问的是同一个对象。他们是这样!

但是,即使我可以看到该对象存在,并且已初始化,并且实际上是正确的对象,但当我尝试调用该对象的方法时,我会立即收到 seg 错误。我尝试了几种不同的方法(包括一些不修改对象的布尔返回)。我再次尝试通过广播器指针和侦听器指针调用它们,只是为了尝试调试。

调试器甚至不进入对象;尝试调用方法时会立即发生段错误。

代码!

/* listeners is a vector of pointers to widgets to whom the broadcasting widget
 * is trying to signal.
 */
unsigned int num_listeners = listeners.size();
for (int w = 0; w < num_listeners; w++)
{
    // Moldable is an abstraction of another widget type
    Moldable* widget = listeners.at(w);

    /* Because in this case, the broadcaster and the listener are one in the same, 
     * these two point to the same location in memory; this part works. I know, therefore,
     * that the object has been instantiated, exists, and is happy, or we wouldn't
     * have gotten to this point to begin with. I can also examine the fields with gdb
     * and can verify that all of this is correct.
     */
    Moldable* broadcaster_debug = broadcast->getBroadcaster();

    /* setStyle is a method I created, and have tested in other instances and it
     * works just fine; I've also used native Wt methods for testing this problem and
     * they are also met with segfaults. 
     */
    widget->setStyle(new_style); // segfault goes here!
}

自从研究将指针存储在向量中并不是最好的想法以来,我已经阅读过,我应该研究 boost::shared_ptr。可能是这样,我会调查它,但它没有解释为什么在已知存在的对象上调用方法会导致段错误。我想了解为什么会这样。

感谢您的任何帮助。

编辑:我已经创建了一个详细的矢量操作要点,因为它的代码比帖子中舒适的要多。 https://gist.github.com/3111137

我没有展示创建小部件的代码,因为它是一种递归算法,为了做到这一点,我必须展示用于创建小部件的整个类决策树。可以说正在创建小部件;在浏览器中查看应用程序时,我可以在页面上看到它们。在我开始使用我喜欢的信号之前,一切都很好。

Moar 编辑:当我查看指令步进模式下的反汇编时,我可以看到就在发生段错误之前,发生了以下操作,其中第一个参数列为'void'。诚然,令我懊恼的是,我对大会一无所知,但这似乎很重要。谁能解释这条指令的含义以及它是否可能是我陷入困境的原因?

 add $0x378,%rax //$0x378 is listed as 'void'

另一个编辑:根据某人的建议,我创建了一个非虚拟方法,我能够在段错误之前成功调用它,这意味着该对象实际上就在那里。如果我采用相同的方法并将其设为虚拟,则会发生段错误。那么,为什么只有虚方法会产生段错误呢?

我现在发现,如果在调用类中,我确保指定 Moldable::debug_test(和 Moldable::setStyle),则不会发生 seg 错误。但是,这似乎与 const 冒泡具有相似的效果——每个虚拟方法似乎都需要这个说明符。我以前从未见过这种行为。虽然我愿意纠正我的代码,如果它真的应该是这样的话,我不确定根本问题是否是别的。

到达那里!

4

1 回答 1

0

好吧,我找到了问题所在,尽管我很遗憾地说这是一个全新的错误,由于项目的性质,很难找到它。我会把答案放在这里,我也投票结束这个问题,因为它过于本地化。请随意做同样的事情。

该类BroadcastMessage有一个__broadcaster字段 ( Moldable* __broadcaster;)。在将指向广播器的指针传递给BroadcastMessage构造函数时,我忘记将入站指针分配给该字段,这意味着 __broadcaster 不是Moldable该类的完全实现的实例。

因此,一些方法实际上是有效的——那些可以内联的方法,或者我为测试创建的虚拟函数(例如,其中一个返回值 1),所以看起来那里有一个完整的对象实际上没有。直到调用一个更专门的方法来尝试访问对象的某些特定的动态属性,才发生段错误。

更重要的是,大部分广播消息的生命周期都在它的构造函数中,这意味着它的大部分目的都可以毫无问题地实现,因为广播器在构造函数的本地范围内是可用的。

但是,按照建议使用 Valgrind,我确实发现了一些其他潜在问题。我也几乎剥离并重新构建了整个项目。我丢弃了大量不必要的代码,作为副作用,它现在运行得更快了。

无论如何,感谢所有的帮助。抱歉,解决方案不是更多的发现。

于 2012-07-18T11:33:06.457 回答