2014-09-18 2 views
1

После некоторых изменений выход приложения в некоторых случаях больше недействителен. Некоторые выходные значения неверны. Значения, используемые для вычисления этих выходов, являются правильными, и в какой-то момент сложной обработки вещи ошибаются.Отслеживать происхождение значения переменной C++

Есть ли инструмент для отслеживания происхождения значения переменной C++? Я раньше использовал valgrind, чтобы отслеживать значения NULL, но то, что мне хотелось бы, является чем-то более общим. Существует ли более общий инструмент, показывающий цепочку (или дерево) назначений, которая привела к тому, что переменная имела свое значение в определенный момент времени?

PS: код, так как почти все унаследованного кода, трудно следовать, не имеет модульных тестов и т.д.

EDIT: Данные точки останова на переменной будет только показать мне конечную точку в цепи. Немного больше, чем было бы неплохо.

+0

Visual Studio позволяет кондиционировать точку останова на переменном изменении: http://stackoverflow.com/questions/160045/break-when-a -value-changes-using-the-visual-studio-debugger – thang

+2

Почему «устаревший код» так трудно следовать? Являются ли комментарии на языках новой функцией? – Bathsheba

+1

Ну, в некотором смысле, значение этой переменной потенциально зависит от всей предыдущей истории вашей программы. Все, что могло бы вычислить такое дерево, может привести к очень большим результатам ... –

ответ

2

Что вы можете сделать, это обернуть интересующие вас переменные семейством общих оберток, которые будут регистрировать stacktrace и значения для каждого вызова. Нечто подобное (опуская некоторые детали):

template <typename T> 
class TracingValue 
{ 
private: 
T m_Val; 
...  
void LogStackTrace() {...} 

public: 

// write 
TracingValue& operator= (const T& val) { 
    LogStackTrace(); 
    m_Val=val; 
    return *this; 
} 

// read  
operator T() const { return m_Val; } 

// "connect" to other values 
TracingValue& operator=(const TracingValue &other) { 
    LogStackTrace(); 
    m_Val = other.m_Val; 
    std::cout << "id: " << this->Id() << " new value: " << m_Val 
      << " from id: " << other.Id() << std::endl; 
    return *this; 
} 

}; 

Вход трассировки стека будет медленным и может генерировать слишком много данных, но если вы используете его экономно, вы можете получить более четкую картину того, что происходит в вашем программном обеспечении. Затем вы можете поместить контрольные точки в оболочку, чтобы поймать изменения, когда они происходят.

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

Возможны изменения стоимости трассировки и конструкции из других завернутых значений. См → Ideone для примера:

TracingValue<double> d; 
d = 3.; 
d = 42.; 
double x = d - 2.; 
std::cout << x << std::endl; 
TracingValue<double> other_d(d); 
TracingValue<double> another_d; 
another_d = other_d; 

вывод

id: 1 constructed with value: 0 
id: 1 new value: 3 
id: 1 new value: 42 
40 
id: 2 constructed with value: 42 
id: 2 constructed from id: 1 
id: 3 constructed with value: 0 
id: 3 new value: 42 from id: 2 
+0

Я не уверен, что OP хочет знать трассировку стека, они хотят знать график зависимостей за этим значением. –

+0

Это действительно так. Я думаю, начиная с малого и постепенно создавая помощников для отслеживания графа объектов, и его эволюция может помочь в любом случае. Представьте себе следующую оболочку, которая будет записывать ссылку на нее в целевое значение. Но, конечно, просто чтение и пошаговая отладка кода может быть лучшим решением общей проблемы. [«Эффективная работа с устаревшим кодом»] (http://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052) должна дать хорошую ссылку, как справиться с задачей. –

+0

Спасибо за внимание. Я могу использовать это в будущем. Но я был готов использовать инструменты для отслеживания происхождения значения в существующей кодовой базе. –

Смежные вопросы