簡體   English   中英

為 std::unordered_map 的專業化注冊 gdb 漂亮打印機

[英]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)正如預期的那樣。 打印mytuplemymap也可以,因為 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM