5

我正在尝试完成以下任务:

  1. 目的。
  2. 用于跟踪目的的具有额外功能的对象的调试版本。

现在,我目前有一个使用宏的编译时解决方案,do {} while(0)如果库没有使用正确的标志编译,它会解析为。

我想将此功能转变为在运行时启用。做这个的最好方式是什么?

我想做:Base * obj = (isGlobalDebugEnabled) ? new Debug(...) : new Base(...);输入东西。我是不是想要这样的东西?

请注意,标准虚函数并不能真正解决问题,因为每个函数都必须在对象的派生(调试)版本中复制,从而违背了目的。

此外,最低级别的函数的容量非常大(分析时调用超过 6000 亿次),所以我想为“基类”编译一个零开销的解决方案。当然,Debug 对象可能更慢。

这就是我想到模板的原因。注意:除了 VS2010 功能(基本 lambda 等)之外,我没有 C++11/boost 访问权限。我可以做类似的事情吗

template <bool debug = false>
class Object {
    std::enable_if<debug> void printTrace(); // Add functions based on debug/not
};
void Object::doSomething(...){
    <only do this if debug without runtime check> addToTrace(...);
    doTheStuff();
}

如果有帮助的话,我看到了这个链接,它把我指向了带有模板的假继承方向。

谢谢您的帮助

AK

编辑:我刚刚意识到我可能会以错误的方式处理它 - 可能将 Debug 对象作为基类,并在 Regular 对象中使用 no-ops 覆盖该功能。这似乎是一个更好的方法。但是,由于这些高性能要求,我仍然想避免 vtable 跳转,所以我猜我的模板问题仍然存在?也许?

EDIT2:正如 KerrickSB 指出的那样,使用示例可能更清楚:

主要exe代码:

void ComputeSomething() {
    Object * obj = (globalDebugFlag) ? new DebugObject(...) : new Object(...);
    obj->insertElement(elem); // Inserts in Object, Inserts and traces actions in DebugObject
    ...
}

其中 Object 当前是一个单独的 DLL,其中globalDebugFlag一个(建议的)全局变量由来自一个单独端口的命令设置,而不是导致调用 ComputeSomething() 的端口。

我计划使用全局跟踪变量,然后通过端口(通过处理此端口的全局对象)将跟踪推回前端工具上显示。

4

2 回答 2

3

根据定义,运行时决策意味着您在运行时而不是编译时做出所有成本的决策。你不会解决这个问题的。

但是,您可以将检查推送到调用堆栈,直到它们很少被命中以满足您的需要,当然,更改调试标志的效果会延迟一点(多少取决于您省略了哪些检查)。使用模板,您可以复制/专门用于调试和非调试版本的代码,而无需复制源代码。

template <bool debug>
class Object {
  void something() {
    // branch on compile-time constant - can be optimized
    if (!debug) return;
    // ...
  }
}

template<bool debug>
useObject(Object<debug> o) {
    for(int i = 0; i < 10000; ++i) {
        // statically calls specialized implementation
        o.something();
    }
}

debugEnabled ? useObject(Object<true>()) : useObject(Object<false>());
于 2013-05-17T17:59:25.280 回答
1

这是一个非常基本的想法。我不确定它是否会推广或扩展,但我们可以讨论。

static bool debug_mode = /* ... */;    // global

class Container
{
    struct ContainerImpl
    {
        virtual ~ContainerImpl() { }
        virtual void insert(int) = 0;
        std::unique_ptr<ContainerImpl> clone() const = 0;
    };

    std::unique_ptr<ContainerImpl> impl;
public:
    Container()
    : impl(debug_mode ? new DebugImpl : new MainImpl)
    { }

    Container(Container const & rhs)
    : impl(rhs.impl->clone())
    { }

    Container(Container && rhs) noexcept
    : impl(std::move(rhs.impl))
    { }

    // also implement assignment


    /*** Main interface ***/

    void insert(int x)
    {
        impl->insert(x);
    }


    /*** Implementations ***/

    struct MainImpl : ContainerImpl { /* main implementation */ };

    struct DebugImpl : MainImpl  // just for example
    {
        virtual void insert(int x)
        {
            // trace insertion
            MainImpl::insert(x);
        }

        std::unique_ptr<ContainerImpl> clone() const
        {
            return { new DebugImpl(*this); }
        }
    };
};

现在您可以将Container其用作普通值类型对象,并且它将根据标志在内部使用不同的实现。

于 2013-05-18T00:12:09.060 回答