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

每个文件启用范围保护

c++
  •  2
  • joce  · 技术社区  · 15 年前

    这是一个小问题,我已经考虑了一段时间,现在我还没有找到解决方案。

    因此,首先,我有一个用于调试的函数保护:

    class FuncGuard
    {
    public: 
        FuncGuard(const TCHAR* funcsig, const TCHAR* funcname, const TCHAR* file, int line);
        ~FuncGuard();
    // ...
    };
    
    #ifdef _DEBUG
        #define func_guard() FuncGuard __func_guard__( TEXT(__FUNCSIG__), TEXT(__FUNCTION__), TEXT(__FILE__), __LINE__)
    #else
        #define func_guard() void(0)
    #endif
    

    该保护旨在通过将一些信息打印到调试控制台来帮助跟踪代码在运行时的路径。其用途如下:

    void TestGuardFuncWithCommentOne()
    {
        func_guard();
    }
    
    void TestGuardFuncWithCommentTwo()
    {
        func_guard();
        // ...
        TestGuardFuncWithCommentOne();
    }
    

    结果是:

    ..\tests\testDebug.cpp(121):
    Entering[ void __cdecl TestGuardFuncWithCommentTwo(void) ]
        ..\tests\testDebug.cpp(114):
        Entering[ void __cdecl TestGuardFuncWithCommentOne(void) ]
        Leaving[ TestGuardFuncWithCommentOne ]
    Leaving[ TestGuardFuncWithCommentTwo ]
    

    现在,有一件事我很快意识到,在函数调用中添加和删除保护是一件痛苦的事情。永久地将它们留在那里也是不可想象的,因为它没有好的理由消耗CPU周期,而且它可以很快让应用程序陷入爬行状态。此外,即使在调试中对应用程序的性能没有影响,调试控制台中很快就会出现大量信息,这些信息会使使用此调试工具变得毫无用处。

    所以,我认为在每个文件的基础上启用和禁用它们是一个好主意。

    其想法是在默认情况下禁用所有功能保护,但只需添加一行,例如

    EnableFuncGuards();
    

    在文件的顶部。

    我想了很多解决办法。因为我的问题已经够长了,所以我不想在这里详细讨论,但是我已经尝试了一些涉及宏的技巧,这些技巧都失败了,其中一个涉及到模板的显式实现,但是到目前为止,没有一个能得到我想要的实际结果。

    另一个需要注意的限制因素是:当前实现函数保护机制的头是通过预编译头包含的。我知道这会使事情复杂化,但如果有人能想出一个在这种情况下可以工作的解决方案,那就太棒了。如果不是,那么,我当然可以从预编译头中提取该头。

    先谢谢你!

    2 回复  |  直到 15 年前
        1
  •  2
  •   Roger Pate    15 年前

    在funcguard中添加一个bool来控制它是否应该显示任何内容。

    #ifdef NDEBUG
      #define SCOPE_TRACE(CAT)
    #else
      extern bool const func_guard_alloc;
      extern bool const func_guard_other;
      #define SCOPE_TRACE(CAT) \
        NppDebug::FuncGuard npp_func_guard_##__LINE__( \
          TEXT(__FUNCSIG__), TEXT(__FUNCTION__), TEXT(__FILE__), \
          __LINE__, func_guard_##CAT)
    #endif
    

    实施文件:

    void example_alloc() {
      SCOPE_TRACE(alloc);
    }
    void other_example() {
      SCOPE_TRACE(other);
    }
    

    这是:

    • 使用特定类别(如果愿意,每个文件包含一个类别)
    • 允许在一个函数中多次使用,每个类别或逻辑作用域一次(通过在变量名中包含行号)
    • 在ndebug构建中编译为零(ndebug是标准的I'm-not-debug宏)

    您将需要一个包含类别bools定义的单个项目范围文件,更改此“设置”文件不需要重新编译程序的任何其他部分(只是链接),因此您可以 get back to work . (这意味着它也可以与预编译头一起工作。)

    进一步的改进包括告诉Funcguard有关类别的信息,这样它甚至可以登录到多个位置。玩得高兴!

        2
  •  1
  •   Michael Burr    15 年前

    你可以做类似的事情 assert() 宏,其中定义了某个宏或未更改 断言() ( NDEBUG 在里面 断言() 的情况)。

    类似以下内容(未测试):

    #undef func_guard
    #ifdef USE_FUNC_GUARD
     #define func_guard() NppDebug::FuncGuard __npp_func_guard__( TEXT(__FUNCSIG__), TEXT(__FUNCTION__), TEXT(__FILE__), __LINE__)
    #else
     #define func_guard() void(0)
    #endif
    

    要记住的一点是,执行此操作的include文件不能包含guard宏(至少不能围绕此部分)。

    然后您可以像这样使用它,这样即使在编译单元中也可以控制跟踪:

    #define USE_FUNC_GUARD
    #include "funcguard.h"
    
    // stuff you want traced
    
    #undef USE_FUNC_GUARD
    #include "funcguard.h"
    
    // and stuff you don't want traced
    

    当然,对于预编译的头文件来说,这并不能100%地发挥作用,但是我认为在预编译之后的头文件的后续包含仍然可以正常工作。即便如此,这可能是不应该出现在预编译头集中的类型。