Индексирование вектора c++ в скрипте python gdb

Я хотел бы написать скрипт python для анализа состояния отладчика алгоритма, но я не могу понять, как заставить базовый пример индексации вектора работать.

например, при отладке следующего файла (gdb_test.cpp):

#include <iostream>
#include <vector>

int main()
{
    std::vector<int> v = {1, 2, 3, 4, 5};
    std::cout << v.size() << std::endl;
    for (const auto& element : v)
    {
        std::cout << element << std::endl;
    }
}

С помощью gdb и получения следующего скрипта (print_vector.py), который предназначен для печати первых трех элементов входного вектора, указанного по имени:

import gdb
class print_vector(gdb.Command):
    def __init__(self):
        super(print_vector, self).__init__('print_vector',
                                           gdb.COMMAND_SUPPORT,
                                           gdb.COMPLETE_FILENAME)

    def invoke(self, arg, from_tty):
        # Access the variable from gdb.
        frame = gdb.selected_frame()

        args = arg.split('; ')
        val = frame.read_var(args[0])

        for i in range(3):
            print(val[0])
print_vector()

С командами:

g++ gdb_test.cpp -std=c++11 -g
gdb ./a.out
(gdb) b gdb_test.cpp:10
(gdb) r
(gdb) source print_vector.py
(gdb) print_vector v

я получаю ошибку

Python Exception <class 'gdb.error'> Cannot subscript requested type.: 
Error occurred in Python command: Cannot subscript requested type.

Что относится к print(val[0])-линии. Проблема в том, что gdb.Value объекты не могут быть проиндексированы как списки. Есть ли другой способ получить доступ к элементам?

Я также пробовал такие вещи, как val['at'][0] и val['at(0)'], ни один из них не работает. Загрузка элементов один за другим с одним вызовом gdb.parse_and_eval работает, но слишком медленно.

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
0
572
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Проблема в том, что объекты C++, открытые для Python, не являются объектами Python «первого класса», поэтому в них нет метода Python __getitem__, который сопоставляется с соответствующим механизмом для получения элемента в классе «C++» объекта.

С другой стороны, API предоставляет метод parse_and_eval, который будет обрабатывать строку, как если бы она была напечатана в исходном коде C++, что позволяет легко использовать v[i] из Python —

В приведенном выше примере вы можете изменить исходный код Python на:

import gdb
class print_vector(gdb.Command):
    def __init__(self):
        super(print_vector, self).__init__('print_vector',
                                           gdb.COMMAND_SUPPORT,
                                           gdb.COMPLETE_FILENAME)

    def invoke(self, arg, from_tty):
        # Access the variable from gdb.
        frame = gdb.selected_frame()

        args = arg.split('; ')
        valname = args[0]

        for i in range(3):
            content_value = gdb.parse_and_eval(f"{valname}[{i}]")
            print(int(content_value))
print_vector()

Чтобы увидеть, как это работает. Для более сложного кода, возможно, стоит создать класс-оболочку в Python для объектов gdb.Value, который будет реализовывать __getitem__, который делает это автоматически.

Я пробовал это, но это очень медленно для больших векторов структур, предположительно из-за накладных расходов в функции parse_and_eval. В идеале должен быть способ получить доступ к элементам непосредственно из полного Value-объекта. Технически это должно быть возможно, так как добавление print(val) к приведенному выше коду дает строку со всеми элементами, что означает, что все они на самом деле загружены в python. В худшем случае, я полагаю, я мог бы разобрать эту строку...

Linus 22.07.2019 17:18
Ответ принят как подходящий

В итоге я использовал следующую функцию в С++ 11:

def vector_to_list(std_vector):
    out_list = []
    value_reference = std_vector['_M_impl']['_M_start']
    while value_reference != std_vector['_M_impl']['_M_finish']:
        out_list.append(value_reference.dereference())
        value_reference += 1

    return out_list

Если std_vector является gdb.Value-объектом, содержащим std::vector<T>, эта функция возвращает список Python из gdb.Value-объектов типа T. На основе этого сообщения в блоге: https://hgad.net/posts/object-inspection-in-gdb/

Я обнаружил, что это значительно быстрее, чем вызов gdb.parse_and_eval['v[i]'] для всех i

Другие вопросы по теме