【问题标题】:What is the meaning of this.attribute when it should be this->attributethis.attribute什么时候应该是this->attribute
【发布时间】:2018-02-16 06:51:16
【问题描述】:

我正在开发一个 C++ 程序,在调试时我在以下函数中:

int CClass::do_something()
{
  ... // I've put a breakpoint here
}

我的CClass有一个属性,我们就叫它att吧。

当我的程序在断点处停止时,我在 Watch 窗口中放置了三件事:

att
this->att
this.att

前两个attthis->att 包含正确的值,但this.att 包含错误的值(至少看起来是错误的)。

它显示价值的事实意味着this.att具有某种意义。 那是什么意思? this.attthis->att相比是什么意思?

供您参考,我使用 Visual Studio 作为开发环境。

【问题讨论】:

  • 您使用的是什么编译器和调试器? Xcode 使用 clang lldb 它实际上为你“修复”了它.. IE: i.imgur.com/fXBfOSE.png 它知道你搞砸了。
  • this 是一个指针,所以你应该使用this->att. 是调用一个方法,指针没有,因为它们是原语,因此该语法是非法的
  • 是的,因此,代码甚至不应该编译,因此您能够调试它很有趣。那么,表达式this.att 是否出现在您的程序中?也许,它只是一个调试器错误(甚至是调试器特定的功能?)
  • @nh_ - 此非法行不在源中。它位于调试器监视窗口中。
  • 我添加了我正在使用 Visual Studio 的信息。在我写这个问题时,我不知道这是相关的。

标签: c++ visual-studio debugging watch


【解决方案1】:

好的,只是在没有更多信息的情况下盲目猜测,但让我试着了解一下您在调试器中看到的内容,因为这是您的问题,对吧?所以我就不解释.->的区别了。假设以下情况:

class CClass 
{ 
    int x; // at offset 0 of CClass
    int att; // at offset 4 of CClass
};

CClass* p = // ... (say p points to the address 0xF0 for now)

int CClass::do_something
{
    CClass q;
    CClass* r;
}

所以,现在在调试器中检查表达式p->att 的值,调试器所做的就是获取p 的值(此处为0xF0)并将att 的偏移量添加到它,导致内存地址0xF4。在该地址读取 4 个字节的内存(因为我们有一个 int)并将其解释为有符号整数。对于上述情况,这应该显示p 指向的对象的att 成员的正确值。

现在,假设您在do_something 函数中,其中有一个CClass 的堆栈分配实例。如果现在尝试获取q.att 的值,调试器会获取对象本身的地址(基本上是&q)并再次添加相应的偏移量4。由于q 是在堆栈上分配的,因此内存片段位于&q + 4 是堆栈帧内存储对象q 的成员att 的值的位置。到目前为止一切都很好。

接下来,考虑表达式r.att,它不是正确键入的 C++,但调试器似乎只是以通常的方式进行。它获取r (&r) 的地址,而不是r 指向的地址,并再次添加att (4) 的偏移量,然后从该位置读取int .由于r 的地址在堆栈上,因此结果位置&r + 4 不是r 指向的对象成员所在的位置,而是堆栈帧内的一个不相关位置(就像在其他局部变量或函数参数)。

在您的情况下,this 也会发生同样的情况。由于this 指针是非static 成员函数的不可见的第一个参数,因此它也位于函数的堆栈帧中。调试器现在似乎获取了堆栈帧中this 指针所在的地址,添加了相应的偏移量并输出在那里找到的4 字节的值。实际值是多少,取决于堆栈帧的布局(可能类似于返回地址),但它显然不在this 指向的对象内。

【讨论】:

    【解决方案2】:

    att 本身返回该类实例的成员变量 att

    this->att 返回与att 相同的内容,只是this-> 明确告诉程序返回类的att 成员变量。

    attthis->att 返回不同值的示例是,如果 att 在类的局部范围内重新定义。在这种情况下,att 将引用本地定义的 attthis->att 将引用该类的 att 成员变量。

    由于this 是指向当前对象的指针,因此它需要-> 表示法(这是解除引用指针和成员/方法访问的组合)。 . 符号仅用于成员/方法访问。要回答您“this.att 的含义是什么”的问题,我会说它毫无意义,老实说,我很惊讶它甚至返回了任何东西。

    您可以将this. 一起使用的唯一“正确”方式是首先取消引用指针,如下所示:

    (*this).att

    但是,如果你只使用->,结果是一样的,语法也是一样的。

    【讨论】:

      【解决方案3】:

      箭头运算符-> 对左侧的pointer 进行操作,这意味着它访问左侧指针所指向的运算符。正如在许多其他地方指出的那样,-> 运算符是手动取消引用指针并使用点符号的简写。 a->b == (*a).b。这意味着它需要查找的上下文信息,它可以通过指针值找到。点运算符. 假定您有一个对左侧对象的引用,因此它不需要先取消引用其左侧的指针。

      如果您的调试器以某种方式允许您使用点运算符而不是箭头运算符,可能是因为它不(或不能)验证所使用的类型,它将假定指针变量的地址,而不是值所指向的地址所持有的地址,就是对象。

      换句话说,它将查看内存中某个位置的对象,而不是对象本身。该行为很可能是未定义的,您只会看到实际存储在成员 att 的内存偏移处的垃圾数据。

      假设你的对象是这样布局的,属性foo在偏移量0,属性att在偏移量4,那么调试器基本上是查看对象实例的地址加上你的偏移量成员变量成立。我不在家里的电脑前,但我可以添加一个草图,稍后澄清一下。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-01-25
        • 2010-11-02
        • 1970-01-01
        • 1970-01-01
        • 2023-04-02
        • 2011-04-15
        相关资源
        最近更新 更多