[英]Registering a gdb pretty-printer for a specialization of std::unordered_map
我正在嘗試為std::unordered_map
的特定專業注冊漂亮打印機,但由於某種原因,它總是在 gdb 中為std::unordered_map
使用標准漂亮打印機,而不是我的專用版本。
考慮以下 class
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)
現在考慮下面的主要function
int main(int argc, char *argv[]) {
std::tuple<int, MyClass> mytuple{10, {"name10", 10}};
std::unordered_map<int, MyClass> mymap;
mymap.insert({10, {"name10", 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
}
這不是很有用。
對於我的特殊需要,我只需要 mymap2 中指向的每個MyClass
mymap2
的“名稱”字段。 然后我為std::unordered_map<int, MyClass *>
創建了一個漂亮的打印機,但我無法正確注冊它(也許只有std::unordered_map
的版本優先,但我無法正確禁用測試這個假設。當我嘗試按照這個問題的建議禁用漂亮打印機時出現錯誤)。
我試過了
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<.*, ns::MyClass\*>', MyUnorderedMapOfMyClassPrinter)
使其適用於 std::unordered_map 專業化pp.add_printer('MyUnorderedMapOfMyClassPrinter', 'std::unordered_map<.*, ns::MyClass\*>', MyUnorderedMapOfMyClassPrinter)
(注意末尾的“*”,因為我只希望它適用於MyClass
指針)。
有趣的是, pp.add_printer('MyUnorderedMapOfMyClassPrinter', 'std::unordered_map<int, ns::MyClass\*>', 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, char *argv[]) {
std::tuple<int, MyClass> mytuple{10, {"name10", 10}};
std::unordered_map<int, MyClass> mymap;
mymap.insert({10, {"name10", 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}});
mymap2.insert({15, new MyClass{"name15", 15}});
mymap2.insert({25, new MyClass{"name25", 25}});
std::cout << "The end" << std::endl;
return 0;
}
以及定義漂亮打印機的完整myprinters.py
文件
class MyClassPrinter:
def __init__(self, val):
self.name = str(val["name"])
self.val = val["value"]
def to_string(self):
return f"MyClass(name={self.name}, value={self.val})"
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})"
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('MyClass', 'MyClass\*', MyClassPointerPrinter)
# pp.add_printer('MyClass', 'MyClass.?\*', MyClassPointerPrinter)
# pp.add_printer('MyClass', 'MyClass \*', MyClassPointerPrinter)
pp.add_printer('MyUnorderedMapOfMyClassPrinter', 'std::unordered_map<.*, ns::MyClass\*>', MyUnorderedMapOfMyClassPrinter)
gdb.printing.register_pretty_printer(gdb.current_objfile(), pp, replace=True)
def my_pp_func(val):
if str(val.type) == "ns::MyClass *":
return MyClassPointerPrinter(val)
gdb.pretty_printers.append(my_pp_func)
對我來說,問題是gdb.current_objfile()
總是返回None
。 因此,您的漂亮打印機被注冊為全局打印機,而所有標准打印機都是 object 級別。 Object 級漂亮打印機優先。
我不知道為什么,但我無法使這個 function 工作。
可以使用此解決方法:
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*
注冊一個漂亮的打印機確實有效,只要我們使用查找 function 而不是依賴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 *) 0x<pointer_address> -> OBJ_REP”的內容,其中“OBJ_REP”是指向 object 的漂亮打印。 如果沒有為ClassName
注冊可視化工具,則僅顯示“(ClassName *) 0x<pointer_address>”。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.