1

有没有什么简单的方法可以std::list<T>在 Metrowerks CodeWarrior 调试器中查看 STL 中的数据?我可以通过查看表达式来查看列表开头或结尾附近的数据,例如

instances->__list_imp.__list_deleter.end_.compressed_pair_imp.second_.prev_->data_

我可以展开结构成员旁边的小“+”号来一次遍历列表一个元素,但这很乏味,并且在大约 20-30 个元素之后,树对于调试器窗口来说太宽了。我正在检查的列表有 2000 多个元素。

CodeWarrior 调试器不支持在表达式中调用函数,所以我无法检查(++(++instances.begin()))或类似的值。我只能查看结构成员,它们的名称非常长且不方便。

调试器窗口也被限制为大约 245 个字符,因此我无法编写脚本来生成一个可笑的长表达式,该表达式将扩展到第 N 个节点。

我正在尝试调试一个需要数小时浸泡才能重现的问题,因此任何需要增量添加代码、重新编译和重新调试的问题都不会很有帮助。但是,如果没有其他选择,那么我可能不得不这样做。

4

3 回答 3

1

这绝对不是一个“简单的方法”(它可能并不比你用“+”做的更容易),但我确实发现在某些情况下它比处理监视视图更有帮助。它还可能允许您在非常糟糕的情况下进行调试(无论出于何种原因,监视视图几乎无法正常工作,或者您只有一个二进制内存转储文件)。

使用 std::list,您通常会在内存中拥有类似这样的实现(如有必要,请参阅 <list> 了解详情):

结构列表
{
  节点 * 下一个;
  节点 * 上一个;
  size_t 大小;
}

模板
结构节点
{
  节点 * 下一个;// 最后一个节点将指向列表而不是另一个节点
  节点 * 上一个;// 第一个节点将指向列表而不是另一个节点
  有效载荷;// 例如在 std::list 中,这将是一个 Foo * 有效载荷
}

请注意,在您的实现中,next 和 prev 的顺序可能相反。

&myList 在大多数实现中基本上等同于“end()”。

如果你使用内存视图,你可以在 &myList 附近闲逛。这将让您找到 myList.prev 或 myList.next 指针的值,然后更改内存视图以查看它。然后,您已分别到达列表中的最后一个或第一个节点。

到达节点后,可以查看 prev、next 或 payload,然后转到 prev 或 next;起泡,冲洗,重复。如果你最终回到 &myList,你就知道你已经遍历了整个事情。

痛苦和无聊?可能。但是您确实对您的 stl 实现非常熟悉,在某些情况下您可以轻松“看到”可能的踩踏,并且当所有其他可能性都飞出窗外时,这是一项有用的技能。

(记下你去过的地方,很容易混淆。)

于 2009-04-29T19:32:51.527 回答
0

调试器当然可以对 STL 更加友好。我对 CodeWarrior 并不特别熟悉,但是您是否根本无法从调试窗口调用任何函数?还是更像我使用的其他调试器,如果程序已经终止(ABORT,segfault,...),您(1)不能调用函数,并且(2)不能调用涉及模板扩展的函数(可能需要向图像添加代码),但是(3)如果代码在断点处停止,可以调用静态链接函数吗?

在后一种情况下,对于您感兴趣的特定类型,您可能希望将一个或多个非模板函数添加到代码中,将 a 复制list<T>到 T 的 C 样式数组中。如果您可以从您的调试窗口,执行此操作,然后检查数组元素以找出列表中的内容。如果您无法从调试窗口调用该函数,您可能需要在代码中靠近错误点的地方对该函数进行一些调用,然后查看结果。如果可能,请保护这些调用,以便仅在设置了一些调试标志时才调用它们。

于 2009-05-01T18:15:00.417 回答
0

事实证明,我遇到的问题是由于列表有几千个元素——它应该只有几十个元素,最多。

在这个特定的 STL 实现中,prev指针存储在每个节点的偏移量 0 处,因此我可以通过重复取消引用来跟踪反向链接。以下怪物向后看 20 个链接:

********************((Metrowerks::node_base**********************)instances->__list_imp.__list_deleter.end_.compressed_pair_imp.second_)

跟随前向链接更难看,因为每次取消引用后必须偏移 4 个字节。

于 2009-05-02T01:49:10.123 回答