使用“this”和“this”之间有区别吗?指针而不使用它?

发布于 2024-11-29 19:18:30 字数 286 浏览 1 评论 0原文

使用“this”指针是否会在运行时向程序添加另一个操作?

举个例子来更好地解释这个问题:

class C
{
public:
    void set_x(int val){ x = val; }
    void set_this_x(int val){ this->x = val; }

private:
    int x;
};

函数“C::set_x()”在运行时执行的操作比“C::set_this_x()”少 1 次吗?

谢谢! :-)

Does using "this" pointer adds another operation to the program at runtime?

Just to give an example to explain the question better:

class C
{
public:
    void set_x(int val){ x = val; }
    void set_this_x(int val){ this->x = val; }

private:
    int x;
};

Does the function "C::set_x()", during runtime, performs 1 less operation than "C::set_this_x()" ?

Thanks! :-)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

烟柳画桥 2024-12-06 19:18:30

两个成员函数之间没有区别。必须如此,因为这是 C++ 标准 (ISO/IEC 14882:2003) 的规定:

9.3.1 非静态成员函数 [class.mfct.nonstatic]

2.id-expression (5.1) 不属于类成员时
访问语法 (5.2.5) 且不用于形成指向成员的指针 (5.3.1)
用于类 X 的非静态成员函数的主体中或
mem-initializer 中用于类 X 的构造函数,如果名称
查找(3.4.1)将id-expression中的名称解析为非静态
XX 基类的非类型成员,
id-expression 转换为类成员访问表达式
(5.2.5) 使用 (*this) (9.3.2) 作为左侧的后缀表达式
. 运算符的。成员名称则指的是该成员
调用该函数的对象。

5.2.5 类成员访问 [expr.ref]

3. 如果 E1 的类型为“指向类 X 的指针”,则表达式
E1->E2 转换为等效形式 (*(E1)).E2; ...

这意味着以下代码:

class C
{
public:
    void set_x(int val) { x = val; }
    void set_this_x(int val) { this->x = val; }
private:
    int x;
};

将被转换为根据 9.3.1/2 和 5.2.5/3 的以下代码:

class C
{
public:
    void set_x(int val)      { (*this).x = val; }   // as per 9.3.1/2
    void set_this_x(int val) { (*(this)).x = val; } // as per 5.2.5/3
private:
    int x;
};

为了表明至少对于一个编译器来说确实没有区别,这里对反汇编进行并排比较VC++ 编译器在禁用优化的情况下发出的 C::set_x()C::set_this_x() 函数 (/Od):

  void set_x(int val){ x = val; }      void set_this_x(int val){ this->x = val; }
push      ebp                        push      ebp
mov       ebp,esp                    mov       ebp,esp
sub       esp,0CCh                   sub       esp,0CCh
push      ebx                        push      ebx
push      esi                        push      esi
push      edi                        push      edi
push      ecx                        push      ecx
lea       edi,[ebp-0CCh]             lea       edi,[ebp-0CCh]
mov       ecx,33h                    mov       ecx,33h
mov       eax,0CCCCCCCCh             mov       eax,0CCCCCCCCh
rep stos  dword ptr es:[edi]         rep stos  dword ptr es:[edi]
pop       ecx                        pop       ecx
mov       dword ptr [ebp-8],ecx      mov       dword ptr [ebp-8],ecx
mov       eax,dword ptr [this]       mov       eax,dword ptr [this]
mov       ecx,dword ptr [val]        mov       ecx,dword ptr [val]
mov       dword ptr [eax],ecx        mov       dword ptr [eax],ecx
pop       edi                        pop       edi
pop       esi                        pop       esi
pop       ebx                        pop       ebx
mov       esp,ebp                    mov       esp,ebp
pop       ebp                        pop       ebp
ret       4                          ret       4

请注意编译器为两个成员函数生成完全相同的程序集

There is no difference between the two member functions. It has to be, since this is what the C++ Standard (ISO/IEC 14882:2003) has to say:

9.3.1 Nonstatic member functions [class.mfct.nonstatic]

2. When an id-expression (5.1) that is not part of a class member
access syntax (5.2.5) and not used to form a pointer to member (5.3.1)
is used in the body of a nonstatic member function of class X or
used in the mem-initializer for a constructor of class X, if name
lookup (3.4.1) resolves the name in the id-expression to a nonstatic
nontype member of class X or of a base class of X, the
id-expression is transformed into a class member access expression
(5.2.5) using (*this) (9.3.2) as the postfix-expression to the left
of the . operator. The member name then refers to the member of the
object for which the function is called.

5.2.5 Class member access [expr.ref]

3. If E1 has the type “pointer to class X,” then the expression
E1->E2 is converted to the equivalent form (*(E1)).E2; ...

So that means the following code:

class C
{
public:
    void set_x(int val) { x = val; }
    void set_this_x(int val) { this->x = val; }
private:
    int x;
};

would've been transformed to the following code according to 9.3.1/2 and 5.2.5/3:

class C
{
public:
    void set_x(int val)      { (*this).x = val; }   // as per 9.3.1/2
    void set_this_x(int val) { (*(this)).x = val; } // as per 5.2.5/3
private:
    int x;
};

To show that there really is no difference, at least for one compiler, here's a side-by-side comparison of the disassembly of the C::set_x() and C::set_this_x() function the VC++ compiler emits with optimizations disabled (/Od):

  void set_x(int val){ x = val; }      void set_this_x(int val){ this->x = val; }
push      ebp                        push      ebp
mov       ebp,esp                    mov       ebp,esp
sub       esp,0CCh                   sub       esp,0CCh
push      ebx                        push      ebx
push      esi                        push      esi
push      edi                        push      edi
push      ecx                        push      ecx
lea       edi,[ebp-0CCh]             lea       edi,[ebp-0CCh]
mov       ecx,33h                    mov       ecx,33h
mov       eax,0CCCCCCCCh             mov       eax,0CCCCCCCCh
rep stos  dword ptr es:[edi]         rep stos  dword ptr es:[edi]
pop       ecx                        pop       ecx
mov       dword ptr [ebp-8],ecx      mov       dword ptr [ebp-8],ecx
mov       eax,dword ptr [this]       mov       eax,dword ptr [this]
mov       ecx,dword ptr [val]        mov       ecx,dword ptr [val]
mov       dword ptr [eax],ecx        mov       dword ptr [eax],ecx
pop       edi                        pop       edi
pop       esi                        pop       esi
pop       ebx                        pop       ebx
mov       esp,ebp                    mov       esp,ebp
pop       ebp                        pop       ebp
ret       4                          ret       4

Note that the compiler produces the exact same assembly for both member functions.

掌心的温暖 2024-12-06 19:18:30

不,它不会产生运行时差异,而只是语法差异。 this 指针仍然在第一个函数中被访问,它只是隐式指定而不是显式指定。

顺便说一句,这听起来像是一种过早的优化——先编写干净的代码,然后再编写快速的代码。

No, it doesn't make a runtime difference, it's just syntax. The this pointer is still accessed in the first function, it's only specified implicitly instead of explicitly.

By the way, this smells like a premature optimization - write clean code first, fast code later.

缺⑴份安定 2024-12-06 19:18:30

如果从类模板继承,则需要 this->member 语法:

template<typename T>
class Base
{
protected:
    T x;
};

template<typename T>
class Derived : Base<T>
{
public:
    void whatever()
    {
        T a = x;         // error
        T b = this->x;   // ok
    }
};

The this->member syntax is required if you inherit from a class template:

template<typename T>
class Base
{
protected:
    T x;
};

template<typename T>
class Derived : Base<T>
{
public:
    void whatever()
    {
        T a = x;         // error
        T b = this->x;   // ok
    }
};
瑾兮 2024-12-06 19:18:30

不,没有区别。
当您直接引用成员时,编译器实际上通过 this 取消引用它。

No, there is no difference.
when you refer a member directly, the compiler actually derefers it through the this.

檐上三寸雪 2024-12-06 19:18:30

是一样的。然而,在某些情况下,“this”可以用来消除歧义。

class C
{
public:
    void set_x(int x){ x = x; } // does nothing
    void set_this_x(int x){ this->x = x; } // sets the variable

private:
    int x;
};

It's the same. However, "this" can be used to disambiguate in certain cases.

class C
{
public:
    void set_x(int x){ x = x; } // does nothing
    void set_this_x(int x){ this->x = x; } // sets the variable

private:
    int x;
};
黄昏下泛黄的笔记 2024-12-06 19:18:30

不。

如果您在某人的代码中偶然发现了该表达式,它可能源自以下内容:

struct A
{
    int x;

    void set_X(int x)
    {
        this->x = x;
    }
};

No.

If you stumbled over that expression in someone's code, it's probably originated in something like this:

struct A
{
    int x;

    void set_X(int x)
    {
        this->x = x;
    }
};
凉城已无爱 2024-12-06 19:18:30

没区别,编译器已经自动生成了这个的代码->虽然它是多余的语法,但使用它有两个很好的理由:

  • 使用支持自动完成的编辑器。当您键入“this->”时,编辑器会弹出一个工具窗口,其中显示可供选择的类成员列表。这可以加快打字速度,并有助于避免由于打字错误而出现愚蠢的编译错误。

  • 它有助于避免必须提出人为的参数名称。您可以为参数指定与类成员相同的名称: void set_x(int x) { this->x = x; }.

No difference, the compiler already automatically generates code for this-> While it is superfluous syntax, there are two good reasons to use it:

  • using an editor that supports auto-completion. When you type "this->", the editor pops up a tool window that presents a list of class members to choose from. This can speed up typing and helps avoid silly compile errors due to typing mistakes.

  • it helps avoiding having to come up with artificial argument names. You can give the argument the same name as the class member: void set_x(int x) { this->x = x; }.

你可以说 foo 而不是 this->foo 只是语法糖。编译后的代码没有区别。像所有语法糖一样,一小部分人谴责它,但大多数人喜欢它。要了解您在这个问题上的立场,请尝试使用 Perl 或 Python 等不提供此语法糖的语言。 Python 代码中充满了 self.foo;在 perl OO 代码中,你会到处看到 self->foo 。这可能会有点分散注意力。

That you can say foo instead of this->foo is just syntactic sugar. There is no difference in the compiled code. Like all syntactic sugar, a small handful decry it but most love it. To see where you stand on the issue, try using a language like perl or python that doesn't provide this syntactic sugar. Python code is peppered with self.foo; in perl OO code you'll see self->foo all over the place. It can be a bit distracting.

套路撩心 2024-12-06 19:18:30

重要的时候之一是当您为局部变量指定与类成员相同的名称时。例如:

class Example {

public:

    int something();
    int somethingElse();

}


int Example::somethingElse() {
    int something = something(); // ERROR
    int something = this->something(); // OK
    // ...
}

One of the times it matters is when you are giving a local variable the same name as a class member. For example:

class Example {

public:

    int something();
    int somethingElse();

}


int Example::somethingElse() {
    int something = something(); // ERROR
    int something = this->something(); // OK
    // ...
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文