【问题标题】:Defining a code section within which a different code path is executed定义执行不同代码路径的代码段
【发布时间】:2018-06-29 15:49:32
【问题描述】:

是否可以在我的代码中定义执行不同代码路径的部分或范围,不使用全局或传递状态变量

出于调试目的,我希望能够用范围或#define 包围一段错误代码,以临时打开此部分中的预定义调试行为,例如使用调试数据、更精确的数据类型、已验证的算法……这需要在多线程应用程序中工作,其中多个线程可能会同时执行相同的共享代码,但只有其中一些线程从内部调用了此代码定义的部分。

例如,这里有一些伪代码不起作用,但可以说明我想要做什么。从多个地方同时调用的静态昂贵函数:

Result Algorithms::foo()
{
#ifdef DEBUG_SECTION
    return Algorithms::algorithmPrecise(dataPrecise);
#else
    return Algorithms::algorithmOptimized(dataOptimized);
#endif
}

其中实例需要经常更新的三个类:

Result A::update()
{
    return Algorithms::foo();
}

Result B::update()
{
    Result result;

#define DEBUG_SECTION
        ...

        result = a.update() + 1337;

        ...
#undef DEBUG_SECTION

    return result;
}

Result C::update()
{
    return a.update();
}

如你所见,A 类直接调用foo(),而在B 类中,foo() 是通过调用a.update() 和其他一些东西间接调用的。让我们假设B::update() 返回一个错误的结果,所以我希望能够仅从这个位置使用foo() 的调试实现。在C::update(),还是应该使用优化后的版本。

我的概念性想法是在错误代码周围定义一个DEBUG_SECTION,它将在此位置使用调试实现。然而,这在实践中是行不通的,因为Algorithms::foo() 被编译一次,而DEBUG_SECTION 没有被定义。在我的应用程序中,AlgorithmsABC 位于不同的库中。

我希望在代码中定义的部分中,执行共享代码中的不同代码部分。但是,在本节之外,我仍然希望执行原始代码,这将在运行时同时发生,因此我不能简单地使用状态变量。我可以在DEBUG_SECTION 中的每个调用中添加一个debugFlag 参数,该参数在每个递归调用中向下传递,然后提供给Algorithms::foo(),但这极容易出错(你不能错过任何调用,但是部分可能非常大,分布在不同的文件中,......)并且在更大的系统中非常混乱。有没有更好的方法来做到这一点?

我需要 C++11 和 MSVC 的解决方案。

【问题讨论】:

  • #if 不能依赖于运行时动态发生的任何事情,它在编译时由预处理器处理。
  • 听起来你应该使用线程局部变量。
  • 我理解为什么这个例子不能工作。但我在编译时已经知道“部分”,我认为可能有一种方法可以将这一点告诉编译器。

标签: c++ c++11 visual-c++


【解决方案1】:

这可以通过使用模板来工作:

template<bool pDebug>
Result Algorithms::foo()
{
    if(pDebug)
        return Algorithms::algorithmPrecise(dataPrecise);
    else
        return Algorithms::algorithmOptimized(dataOptimized);
}

另一方面,这意味着将您的函数定义移动到标题中(或强制模板实例化,请参阅these answers)。

不利的一面是,每次您想在调试和发布之间切换时,将对 Algorithms::foo() 的调用从 instance.foo&lt;false&gt; 更改为 instance.foo&lt;true&gt; 可能需要付出一些努力。如果您有多个受影响的调用,您可以使用编译时 const 变量来减少输入工作量,但不完全了解您的代码我无法估计这是否是一个可行的解决方案。

如果您的大部分代码使用函数的优化版本,您还可以将模板参数设置为默认为 false (template&lt;bool pDebug = false&gt;),以避免更改不会调用调试版本的现有代码。

【讨论】:

  • 虽然这比传递调试参数更优雅,但对于较大的软件项目来说是不可行的。然而,这至少是一个答案。谢谢!
猜你喜欢
  • 2011-02-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-17
  • 1970-01-01
  • 2012-06-06
  • 1970-01-01
相关资源
最近更新 更多