65.9K
CodeProject 正在变化。 阅读更多。
Home

调试 C++ 公共成员变量的修改/访问

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.66/5 (10投票s)

2006年11月20日

3分钟阅读

viewsIcon

27234

使用运算符重载来调试公共成员变量的修改/访问的一个技巧

引言

在许多 C++ 维护/增强项目中,public 成员变量是一个现实,特别是当这些项目从 C 转换为 C++ 时。在这些项目中,我在调试时不断遇到的一个问题是如何设置断点,以便找出某个 public 成员变量何时被修改或被访问。这些成员变量通常是基本的 C、C++ 类型,如 intdouble 等。导致这种情况的常见原因是 C 结构体被提升为 C++ 类,而没有任何访问器或修改器方法。这通常发生在 C 到 C++ 的迁移过程中,为了加快项目速度,或者有时是因为一些懒惰的同事使用了 public 成员变量作为捷径。

为什么如此令人沮丧?

令人沮丧的是,看到相同的成员变量名称被用在 10 个不同的类中,而这 10 个不同的类又被用在 100 个不同的文件中。当你搜索该变量时,你会得到 1000 个结果,并且一直想知道这些结果中哪一个是我的类实例被修改的正确位置。如果你经常遇到这种麻烦,那算你幸运。

调试时有哪些选择?

在 Visual Studio 调试器中,有一些可用的解决方案可以解决这个问题。最受欢迎的一种是在成员变量被修改时设置断点。这个解决方案在大多数情况下都运行良好。但是有一个限制 - 必须在运行时为类实例上下文中的修改设置断点,并且你必须很好地了解执行流程才能获得正确的实例。当你有很多类实例时,你不知道哪个特定的类才是你真正感兴趣的。在正确的上下文中设置断点之前,你将不得不付出很多努力,或者在最坏的情况下,你不知道执行流程,并且无法找到你感兴趣的任何上下文。

无论如何,没有办法设置断点来检查成员变量何时被访问。

“问题代码”

让我们看看代码对于我所说的调试问题是什么样的...

class RequestA
{
public:
    //Other member variables
    int v1;
    int v2;
    //member variable of our interest
    int status;
};

class RequestB
{
public:
    //Other member variables
    int v3;
    int v4;
    //member variable of our interest
    int status;
};

void UserFunction1(int condition)
{
    RequestA reqA1;
    RequestA reqA2;
    RequestB reqB1;
    RequestB reqB2;

    reqA1.status = 0;
    reqA2.status = reqA1.status;
    reqB1.status = reqA1.status;
    if (reqB1.status == 0)
    {
        reqB2.status = reqB1.status;
    }
    
    switch(condition)
    {
    case 10:
        //Some code            
        //
        //
        //
        reqA2.status = 0;
        //some other processing
        //
        reqB1.status = 0;
        //Some code
        //
        //
        //
        reqA1.status = 2;
    case 11:
        reqA1.status = 3;
        //Some code
        //
        //
        //
        reqA2.status = 0;
        //Some code
        //
        //
        //
        reqB1.status = 0;
    case 16:
        reqA1.status = 3;
        //Some code
        //
        //
        //
        reqB2.status = 4;
        //Some code
        //
        //
        //
    case 19:
        reqA1.status = 5;
        //Some code
        //
        //
        //
        reqA1.status = 3;
        reqB1.status = 3;
    }
}

void UserFunction2(int anotherCondition)
{
    RequestA reqA1;
    RequestA reqA2;
    RequestB reqB1;
    RequestB reqB2;
    reqA1.status = 1;
    reqA2.status = 2;
    reqB1.status = 3;
    reqB2.status = 4;
    //Some complex and long algorithm modifying status variable
    //...
    //...
    reqA1.status = reqA2.status;
    reqA2.status = reqB1.status ;
    reqB1.status = reqB2.status ;
    reqB2.status = reqA2.status;
}

我为修改或访问设置断点的解决方案

在这种情况下,我发现以下简单的 C++ 技巧非常有用,可以捕获修改 public 变量的代码。我围绕基本的 int 定义一个包装类,我们称之为 BasicIntWrapper。它提供了提取 int 值并将其分配回去所需的运算符。

class BasicIntWrapper
{
    int m_i;
public:
    operator int()
    {
        return m_i;
    }
    int operator = (const int& value)
    {
        return (m_i = value);
    }
    //Some more additional operators as needed..
    //...
    //...
    //...
};

现在,对于调试版本,让我们将类成员状态细化为 BasicIntWrapper status; 让我们看看重新定义的类 RequestB

class RequestB
{
public:
    //Other member variables
    int v3;
    int v4;
    //member variable of our interest
#ifdef _DEBUG
    BasicIntWrapper status;
#else
    int status;
#endif
};

一个更好的方法是将此包装类定义为 RequestB 的成员类。这在两个方面有所帮助

  1. 捕获每个类的修改
  2. 处理名称冲突

class RequestB
{
public:
    //Other member variables
    int v3;
    int v4;
    //member variable of our interest
#ifdef _DEBUG
    class BasicIntWrapper
    {
        int m_i;
    public:
        operator int()
        {
            return m_i;
        }
        int operator = (const int& value)
        {
            return (m_i = value);
        }
        //Some more additional operators as needed..
        //...
        //...
        //...
    };
    BasicIntWrapper status;
#else
    int status;
#endif
};

现在,如果在类 BasicIntWrapper 的运算符中设置断点,您将捕获所有类范围的修改。

最终评论

我的经验是 - 对于这个问题没有银弹,但是这个技巧有助于在很大程度上改进断点的位置,然后再在 Visual Studio 中使用断点。

作者:Vishal Jadhav
电子邮件:vishalya@yahoo.com

© . All rights reserved.