问题描述
我正在尝试为 std::unordered_map
的特定专业注册一个漂亮的打印机,但出于某种原因,它总是在 gdb 中为 std::unordered_map
使用标准的漂亮打印机,而不是我的专业版本。
考虑下面的类
namespace ns {
class MyClass {
public:
std::string name;
int value = 0;
};
} // namespace ns
我为它定义了一个 gdb 漂亮的打印机
# myprinters.py -> sourced in gdb
class MyClassprinter:
def __init__(self,val):
self.name = val["name"]
self.val = val["value"]
def to_string(self):
return f"MyClass(name={self.name},value={self.val})"
import gdb.printing
pp = gdb.printing.RegexpcollectionPrettyPrinter('myprinters')
pp.add_printer('MyClass','MyClass',MyClassprinter)
gdb.printing.register_pretty_printer(gdb.current_objfile(),pp,replace=True)
现在考虑下面的主要功能
int main(int argc,char *argv[]) {
std::tuple<int,MyClass> mytuple{10,{"name10",10}};
std::unordered_map<int,MyClass> mymap;
mymap.insert({10,10}});
mymap.insert({15,{"name15",15}});
mymap.insert({25,{"name25",25}});
auto myobj = MyClass{"name5",5};
std::unordered_map<int,MyClass *> mymap2;
mymap2.insert({10,new MyClass{"name10",10}}); // don't worry about the new
mymap2.insert({15,new MyClass{"name15",15}});
mymap2.insert({25,new MyClass{"name25",25}});
std::cout << "The end" << std::endl;
return 0;
}
如果在 cout
行中添加断点并按预期打印 myobj
我得到 $7 = MyClass(name="name5",value=5)
。打印 mytuple
和 mymap
也有效,因为 gdb 为 STL 中的容器提供了漂亮的打印机。我们得到类似
$8 = std::tuple containing = {
[1] = 10,[2] = MyClass(name="name10",value=10)
}
$9 = std::unordered_map with 3 elements = {
[25] = MyClass(name="name25",value=25),[15] = MyClass(name="name15",value=15),[10] = MyClass(name="name10",value=10)
}
然而,我实际拥有的是带有 MyClass*
而不是 MyClass
的容器,例如 mymap2
变量。打印结果
$10 = std::unordered_map with 3 elements = {
[25] = 0x555555576760,[15] = 0x555555576710,[10] = 0x555555576650
}
这不是很有用。
对于我的特殊需要,我只需要 MyClass
中指向的每个 mymap2
对象的“名称”字段。然后我为 std::unordered_map<int,MyClass *>
创建了一个漂亮的打印机,但我无法正确注册它(也许只是 std::unordered_map
的版本优先,但我无法正确禁用来测试这个假设。当我尝试按照 this question 中的建议禁用漂亮打印机时出现错误。
我试过
class MyUnorderedMapOfMyClassprinter:
def __init__(self,val):
self.val = val
def to_string(self):
return "MyUnorderedMapOfMyClassprinter"
然后将下面的行添加到定义我的漂亮打印机的 python 脚本中
pp.add_printer('MyUnorderedMapOfMyClassprinter','std::unordered_map<int,ns::MyClass\*>',MyUnorderedMapOfMyClassprinter)
包括新的漂亮打印机。
但是打印 unordered_map 不使用我的漂亮打印机。它仍然使用来自 gdb 的常规 std::unordered_map
漂亮打印机。
如果我确实创建了一个新类型
class MyUnorderedMap : public std::unordered_map<int,MyClass *> {};
并为 MyUnorderedMap
注册一个漂亮的打印机,然后它就可以工作了。但我不想创建另一种类型只是为了能够注册一个漂亮的打印机。
如何为 std::unordered_map
的特定专业注册漂亮的打印机?
编辑:
我不能只禁用 std::unordered_map
漂亮的打印机,但是
我在 gdb 中使用 disable pretty-printer
禁用了所有漂亮打印机,然后使用 enable pretty-printer global myprinters
仅启用了我的漂亮打印机。这使我可以尝试使用正则表达式来注册我的漂亮打印机,并使其适用于带有 pp.add_printer('MyUnorderedMapOfMyClassprinter','std::unordered_map<.*,MyUnorderedMapOfMyClassprinter)
的 std::unordered_map 专业化(注意末尾的“*”,因为我只希望它适用于 { {1}} 个指针)。
有趣,MyClass
没有用。出于某种原因,我不得不使用 pp.add_printer('MyUnorderedMapOfMyClassprinter',MyUnorderedMapOfMyClassprinter)
而不是 .*
才能使其工作。
然而,当所有漂亮打印机都启用时,标准的 int
漂亮打印机仍然优先于我的专业化。 如何让漂亮的打印机优先?
为了让事情更容易重现,这里是完整的 std::unordered_map
文件
main.cpp
以及定义漂亮打印机的完整 #include <iostream>
#include <string>
#include <tuple>
#include <unordered_map>
namespace ns {
class MyClass {
public:
std::string name;
int value = 0;
};
} // namespace ns
using namespace ns;
int main(int argc,10}});
mymap2.insert({15,25}});
std::cout << "The end" << std::endl;
return 0;
}
文件
myprinters.py
解决方法
对我来说,问题是 gdb.current_objfile()
总是返回 None
。因此,您的漂亮打印机被注册为全局打印机,而所有标准打印机都是对象级别的。对象级漂亮打印机优先。
我不知道为什么,但我无法使这个功能工作。
可以使用此解决方法:
gdb.printing.register_pretty_printer(gdb.objfiles()[0],pp,replace=True)
,
在“n.'pronouns' m.”的问题中进行了更多的调查和评论后,我能够解决问题,尽管问题在技术上仍然没有解决。
总而言之,与
class MyUnorderedMapOfMyClassPrinter:
def __init__(self,val):
self.val = val
def to_string(self):
return "MyUnorderedMapOfMyClassPrinter"
import gdb.printing
pp = gdb.printing.RegexpCollectionPrettyPrinter('myprinters')
pp.add_printer('MyClass','^ns::MyClass$',MyClassPrinter)
pp.add_printer('MyUnorderedMapOfMyClassPrinter','std::unordered_map<.*,ns::MyClass\*>',MyUnorderedMapOfMyClassPrinter)
为我的 unordered_map
专业注册了一台漂亮的打印机。但是,仍使用通用 unordered_map
的版本,如果我打印 mymap2
变量,则字符串 "MyUnorderedMapOfMyClassPrinter"
未显示正如预期的那样。如果我们禁用所有漂亮的打印机并仅启用我们的漂亮打印机,则会显示“MyUnorderedMapOfMyClassPrinter”,从而确认它已正确注册。这就是问题在技术上没有解决的原因,因为禁用所有其他漂亮的打印机并不是一个好的解决方案。
但是为 MyClass*
注册一个漂亮的打印机确实有效,正如评论中所建议的那样,只要我们使用查找函数而不是依赖于 RegexpCollectionPrettyPrinter
。这解决了最初的问题,因为 unordered_map
的 gdb 常规漂亮打印机现在就足够了。
更具体地说,我们可以创建一个漂亮的打印机
class MyClassPointerPrinter:
def __init__(self,val):
self.ptr = val
self.name = str(val.dereference()["name"])
self.val = val.dereference()["value"]
def to_string(self):
return f"Pointer to MyClass(name={self.name},value={self.val})"
并注册
def my_pp_func(val):
if str(val.type) == "ns::MyClass *":
return MyClassPointerPrinter(val)
gdb.pretty_printers.append(my_pp_func)
我们甚至可以进一步扩展它,为任何指针创建一个漂亮的打印机。例如,我们可以将漂亮的打印机定义为
class MyPointerPrettyPrinter:
def __init__(self,val):
self.ptr = val
def to_string(self):
default_visualizer = gdb.default_visualizer(self.ptr.dereference())
return f"({self.ptr.type}) {self.ptr.format_string(raw=True)} -> {default_visualizer.to_string()}"
并注册
def my_pointer_func(val):
# This matches any pointer
if val.type.code == gdb.TYPE_CODE_PTR:
# Only if the pointed object has a registered pretty-printer we will use
# our pointer pretty-printer
if gdb.default_visualizer(val.dereference()) is not None:
return MyPointerPrettyPrinter(val)
gdb.pretty_printers.append(my_pointer_func)
这将匹配任何指针并打印类似“(ClassName *) 0xClassName
注册的可视化工具,则只显示“(ClassName *) 0x