代码之家  ›  专栏  ›  技术社区  ›  villintehaspam

便于调试的编码

  •  1
  • villintehaspam  · 技术社区  · 14 年前

    我正在寻找如何通过向应用程序添加代码来帮助调试的技巧。一个让我更清楚我在追求什么的例子:为了检测由共享指针持有的悬空对象,我创建了一个跟踪类,允许我跟踪有多少个对象是活动的,以及它们最初创建的位置,然后这样使用:

    class MyClass {
        TRACK_THIS_TYPE(MyClass);
    };
    
    boost::shared_ptr<MyClass> myObj(new MyClass);
    TRACK_THIS_OBJECT(myObj);
    

    其中track_this_type(t)是一个宏,它确保我获得一个类的实例计数(以及创建了多少个对象的计数),track_this_object是一个宏,它存储创建对象的文件和行以及对象的弱指针。

    这允许我检测悬空的物体以及它们在哪里创建。它不允许我找出哪些对象对我的对象持有共享的指针,这可能是对上述内容的改进。我想可以创建一个类似track_this_ptr(t)宏的宏,它将存储创建共享_ptr实例的文件和行。

    另一个例子是

    assert(condition && "My descriptive text");
    

    这允许您将有意义的注释直接放入断言中。

    是否有任何人可以用干净的C++技巧来收集统计数据、自动堆栈跟踪、跟踪对象/指针/资源、死锁/饥饿或其他线程问题,确保异常在某个地方得到处理,文档帮助还是类似的?任何事情都是真的,不管是有助于防止错误还是事后有所帮助。

    编辑: 除了回答这个问题,我还收到了一些关于 google-glog 作为日志记录实用程序。

    6 回复  |  直到 14 年前
        1
  •  2
  •   Alexander Gessler    14 年前

    以下主要是为了便于调试 之后 释放。

    Stackwalker 类似的工具提供了一种简单的方法,可以在没有激活调试器的情况下,在最终用户机器上获得可用的调用堆栈。相当相似, Google Breakpad 可用于从崩溃的进程中轻松提取小型转储。

        2
  •  4
  •   Tristram Gräbener    14 年前

    我经常使用boost断言来检查输入、中间计算和返回之前,即使它看起来很明显。

    它迫使您考虑哪些值可以带您获取数据,并使您更容易快速地找到一个重构,这会留下一些愚蠢的错误。

    如果你真的关心性能,你可以在发布版本中禁用它们。

    关于内存管理,我大量使用RAII,并尽我所能地使用尽可能少的指针和手动内存分配。当代码中只有2或3个指针时,更容易避免出错。

        3
  •  3
  •   Matthieu M.    14 年前

    有趣的是,为了跟踪内存问题,我们在工作中有一个非常类似的项目。

    很多人都对RAII发誓,但甚至使用 shared_ptr 您可以创建泄漏,问题主要是由于引用循环(这就是基于引用计数的垃圾收集器具有检测循环的特殊算法的原因):x

    我为(Amadeus)工作的公司目前正在开发中 AMPolice 哪一个再充电 valgrind . 它仍在进行中,特别是在文档部门。

    如您所见,这与您自己的方法完全不同:二进制文件保持不变,并且在必要时(使用命令行API)通过切换到“调试”内存管理(在运行时)来跟踪内存分配。

    因此,这更容易使用,尽管从我们的测试来看,它确实会影响计时(4x或5x)。

    该工具是非常通用的,因此通常可以被许多人使用,但当然,主要问题仍然是日志的剪切大小,因为跟踪每一个 new 相当昂贵:x

        4
  •  1
  •   monojohnny    14 年前

    你可以用“log4cxx”之类的东西来记录你正在生成的统计数据。

    http://logging.apache.org/log4cxx/index.html

    这应该允许您控制运行时正在进行的跟踪级别(或者至少通过运行时读取的配置文件)。

    它将自动为日志设置时间戳,并允许您将输出格式化为适合其他工具(例如Excel或数据库),以便对日志数据进行统计分析。

        5
  •  1
  •   anon    14 年前

    我个人倾向于一开始就不写bug。向应用程序中添加大量调试代码可能会产生不幸的副作用。它显然会影响性能,在多线程应用程序的情况下,它可以更改应用程序的时间,从而隐藏mt错误。

    我发现我通常只花很少的时间调试我的代码——而任何我花在调试器上的时间我都算作浪费的时间。我发现有帮助的是,在我做了每一个更改之后,我都可以运行测试——您不必使用TDD来使用这种方法。

        6
  •  0
  •   yazz.com    14 年前

    我的C++现在有点生疏了,但我确实记得每当我要分配一个对象时,我就有一个宏执行它:

    新(班)

    然后是释放对象的宏。然后,每个宏将存储创建和销毁对象的类和行号。

    这样就可以通过查看对象未被释放的位置来轻松检测内存泄漏。