【问题标题】:Track the origin of a C++ variable's value跟踪 C++ 变量值的来源
【发布时间】:2014-09-18 08:12:28
【问题描述】:

在某些情况下,经过一些更改后,应用程序的输出不再有效。一些输出值是错误的。用于计算这些输出的值是正确的,但在复杂的处理过程中,某些时候会出现错误的情况。

是否有工具可以跟踪 C++ 变量值的来源?我以前使用 valgrind 来跟踪 NULL 值,但我想要的是更通用的东西。 是否有更通用的工具可以显示导致变量在某个时间点具有其值的赋值链(或树)?

PS:该代码与几乎所有遗留代码一样,难以遵循,没有单元测试等。

编辑:变量上的数据断点只会显示链中的端点。多一点就好了。

【问题讨论】:

  • 为什么“遗留代码”如此难以理解?语言 cmets 是新功能吗?
  • 嗯,从某种意义上说,该变量的值可能取决于您程序的整个先前历史。任何可以计算出这样一棵树的东西都可能产生一些非常大的结果......
  • 这是一个奇怪的现象。偶尔你会接到猎头电话,解释说某些投资银行或其他银行有“大量遗留代码”需要重构。这真正意味着它是被一群在阴沟里学会了语言的人一起破解的。我猜想今天写的很多代码在未来几年都会是类似的。那部电话肯定会继续响铃。让我们都停止编写遗留代码!
  • 根据应用程序的类型,这介于“容易”到“非常困难”之间。变量可以通过多种不同的方式改变,如果你写一些东西来“跟踪一个变量”,我几乎可以保证我可以写一些东西让你的应用程序不知道发生了什么,然后你想出更聪明的东西,我想出了更聪明的东西。没有简单的答案,唯一的出路是跟踪您的计算,使用调试器 - 记录您进行的过程,无论是单独还是在代码中。
  • @pau.estalella 我的意思是,“确切的分配顺序”可能是一个巨大的图,它的实际价值很小。

标签: c++ debugging


【解决方案1】:

您可以做的是使用一系列通用包装器来包装您感兴趣的变量,这些包装器将记录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

【讨论】:

  • 我不确定 OP 是否想知道堆栈跟踪,他们想知道该值背后的依赖关系图。
  • 确实如此。我认为,从小处着手,逐步创建助手来跟踪对象图及其演变,无论如何都会有所帮助。想象一个进一步的包装器,它将某种类型的引用记录到目标值中。但是,当然,仅仅阅读和逐步调试代码可能是解决整体问题的更好方法。 "Working Effectively With Legacy Code" 也应该为如何完成任务提供很好的参考。
  • 感谢您的努力。我将来可能会使用它。但我希望准备好使用工具来追踪现有代码库中值的来源。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-24
相关资源
最近更新 更多