使用“this”指针而不使用它有什么区别吗?

时间:2011-08-13 09:12:29

标签: c++ performance this

使用“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次操作?

谢谢! : - )

9 个答案:

答案 0 :(得分:19)

两个成员函数之间没有区别。它必须是,因为这是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的构造函数,如果是name   lookup(3.4.1)将id-expression中的名称解析为非静态名称   类X的非类型成员或X的基类,   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

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

答案 1 :(得分:9)

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

顺便说一句,这有点像过早的优化 - 先编写干净的代码,然后再编写快速的代码。

答案 2 :(得分:6)

如果从类模板继承,则需要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
    }
};

答案 3 :(得分:3)

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

答案 4 :(得分:3)

它是一样的。但是,在某些情况下,“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;
};

答案 5 :(得分:2)

没有。

如果你在某人的代码中偶然发现了这个表达,那么它可能起源于这样:

struct A
{
    int x;

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

答案 6 :(得分:2)

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

  • 使用支持自动完成的编辑器。当您键入“this-&gt;”时,编辑器会弹出一个工具窗口,其中显示可供选择的班级成员列表。这可以加快输入速度,并有助于避免因输入错误而导致的错误编译错误。

  • 它有助于避免不得不提出人工参数名称。您可以为参数赋予与类成员相同的名称:void set_x(int x){this-&gt; x = x; }。

答案 7 :(得分:2)

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

答案 8 :(得分:1)

重要的一点是当你给一个与类成员同名的局部变量时。例如:

class Example {

public:

    int something();
    int somethingElse();

}


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