我的C++实践(2):模板代码的测试

     C++中的模板产生类代码的过程非常复杂,而模板所表示的泛型代码还要依赖于使用模板的客户端。比如模板本身的位置、使用模板的位置、定义模板实参的位置等都会对模板的实例化产生影响。因此,模板代码的测试和调试都比较难。跟踪程序(tracer)就是一种可以跟踪模板实际调用步骤的程序,它通常是一个用户自定义的类,只定义了满足模板测试的一些功能。类的每个操作中都有一个针对该操作的跟踪(比如递增一个计数变量,以记录该操作的调用次数)。用这个类作为模板的实参来使用模板,就可以测试模板的功能。
    跟踪程序是一种比较简单和行之有效的技术,它虽不能测试出模板代码中的所有错误,但可以在开发周期的早期检测出模板定义中的很多问题,这样就可以减轻后期调试的负担。当我们用C++开发模板代码时,使用跟踪程序是一种比较好的测试技巧。
   下面开发一个跟踪程序Tracer,并用它测试排序算法std::sort(这是一个函数模板),这可以确认算法的效率和操作的实际调用步骤。类Tracer是跟踪程序,它可以跟踪算法运行时产生对象拷贝的份数、调用构造函数的次数、调用析构函数的次数、对象赋值的次数、对象比较的次数、现存对象的最大个数等。 

   用这个跟踪程序来测试排序算法。如下:

   运行结果如下:

    这里“Tracer creation #1, created as generation 1 (total: 1)“表示第1次创建对象(直接创建),被创建为第generation份拷贝(首次创建时表示第1份拷贝,以后调用复制构造函数时,拷贝份数会增加),total表示现存对象的总个数。
    “Tracer creation #11, copied as generation 2 (total: 11)“表示第11次创建对象(通过复制构造函数创建),被复制为第generation份拷贝。
    “Tracer comparison #1 (generation 2 < 1)“表示第1次比较,比较左边对象的第2份拷贝是否小于右边对象的第1份拷贝。
    “Tracer assignment #1 (generation 1 = 1)“表示第1次赋值:把右边对象的第1份拷贝赋给左边对象的第1份拷贝。
    “Tracer destruction #1, generation 2 destroyed (total: 10)“表示第1次销毁对象,当前对象的第2份拷贝被销毁。
    从最后的统计报告中可以看出,对10个对象运行std::sort算法进行排序,总共创建了15个临时对象,但在同一时刻最多只存在2个多余的对象(最多有12个,减去要排序的10),这让我们对算法的开销有了基本的把握。运行也说明了我们的tracer完全满足标准sort()算法的要求,例如不需要运算符==和运算符>。从输出的排序结果可以看出基本上没有问题。特别要注意这只是一个大概的判断,它并不能断定算法的内部代码实现的完全正确性。


     对tracer增加断言和推理,或者连接到推理引擎(是一个程序,可以记住用来推导出结论的断言和推理)等,就可以扩展成所谓的oracles(测试谕示)。oracles可以动态地验证算法,它不需要完全指定模板实参(oracles本身就是实参),也不需要在程序中指定输入数据(推理引擎会请求用户来输入)。当前使用oracles对算法复杂度的分析也是非常有限的。
    tracer是跟踪模板所需要的最小接口。当tracer不产生运行期输出时,我们有时也称之为archetype(原型)。利用archetype我们可以验证模板是否会请求不符合期望的语法约束。对于一个模板的实现,我们一般要为模板库中标记的每个concept都开发一个archetype。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值