8

在 C++ 代码中查找未实例化模板的最佳方法是什么?

我有一个大量使用模板的代码库。当然,我们要确保测试覆盖率很高。对于所有使用过的代码,使用gcov.

但是,未使用的模板被报告为不可执行gcov

经过一番谷歌搜索,似乎没有办法强制g++为这些模板发出代码(这只是合乎逻辑的,编译器应该如何猜测任何类型?)似乎也没有办法让 gcov 识别未实例化的模板代码作为可运行代码。

有什么“开箱即用”的东西可以让我扩充 GCC-ftest-coverage -fprofile-arcs仪器生成的文件吗?根据GCC 的 gcov 选项文档,将整个模板函数体标记为一个块可能就足够了,因为执行永远不会在那里结束。

编辑(背景信息):我正在开发一个只有标题的模板库。我的目标是找到未使用/未经测试的功能。

我知道代码覆盖率是有缺陷的,但是找到未实例化的代码是朝着更好地测试代码迈出的非常重要的一步。目前,我们将检查点宏放在每个函数的开头。在测试模式下,它们扩展为将一对插入(file, line)到一组已通过检查点的全局代码。运行测试后,我们手动读取所有文件并将到达的检查点与所有可用检查点的集合进行比较。

查找未实例化的代码很重要,例如,由于不直观的 C​​++ 模板优先行为,可能会有读者甚至作者希望使用的死代码。

4

3 回答 3

2

从您的角度来看, 我认为我们的C++ 测试覆盖工具(不是基于 GCC)正确地做到了这一点。

它在编译器看到源代码之前对其进行检测;无论模板是否被使用,模板内的代码都会获得“覆盖探测”。该工具的测试覆盖率显示部分知道所有探针的位置;如果模板代码没有被实例化,它显然不能被执行,这就是将被报告的内容。您不必进行任何“自定义”宏插入或其他,呃,BS。

不利的一面是,如果您有一个由几种不同类型参数化的模板,并且为不同的实例化类型执行模板方法 m1 和 m2,则 m1 和 m2 的覆盖率将是 100%(毕竟,您执行了插桩模板)。目前尚不清楚这很糟糕。只是这就是解释的方式。

于 2011-04-26T00:10:25.253 回答
1

好的,因为我不太熟悉 GCC,所以这是一个乏味且非常耗时的解决方案,但至少它有效!:)
这个测试依赖于这样一个事实,即模板代码中的一些错误直到实际实例化才被检测到,即当依赖名称实际上不存在于模板参数中时:

template<class T>
struct Example{
  typedef typename T::_123344_non_existent_type instantiation_test;
};

将这样的 typedef 添加到您拥有的每个模板中,然后编译。从编译器显示错误的每个结构/类/函数中删除它,并且当代码最终编译时,每个仍然包含此类 typedef 的模板永远不会被实例化。或者你很不幸,有些类型确实定义了这样的 a _123344_non_existent_type,尽管我会私刑负责那个的同事。;)

于 2011-04-25T21:38:12.503 回答
1

我遇到了同样的问题,所以我编写了一个程序来修改代码覆盖率报告以显示未实例化的模板。它不是最优雅的,但它确实有效。

有两个阶段:

  • 在编译之前,您使用使用 Clang 的 Libtooling 编写的 C++ 程序来查找代码中的所有模板并在它们之前和之后插入注释。
  • 生成测试覆盖率报告后,您运行一个 Python 脚本,该脚本会检查报告并修改步骤 1 中的注释所包含的行。

所以基本上它利用了这样一个事实,即使你的很多代码都被排除在二进制文件之外,它几乎都最终出现在最终的覆盖率报告中。这个问题中描述的宏是这种方法的灵感来源(它基本上是它们的自动化版本,不会弄乱源代码)。

到目前为止,我只在自己的代码中使用过它,但它应该泛化。欢迎提出问题和请求请求!

于 2018-06-16T22:34:43.083 回答