Есть ли разница между использованием указателя «this» и его неиспользованием? - PullRequest
11 голосов
/ 13 августа 2011

Добавляет ли указатель "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 ()" во время выполнения выполняет на 1 операцию меньше, чем "C :: set_this_x ()"?

Спасибо! : -)

Ответы [ 9 ]

19 голосов
/ 13 августа 2011

Нет никакой разницы между двумя функциями-членами.Должно быть так, поскольку это то, что в стандарте 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для нестатического нетипичного члена класса 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;
};

Чтобы показать, что тамна самом деле нет никакой разницы, по крайней мере, для одного компилятора, вот параллельное сравнение дизассемблирования функции C::set_x() и C::set_this_x(), которую компилятор VC ++ генерирует с отключенной оптимизацией (/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

Обратите внимание, что компилятор создает точно такую ​​же сборку для обеих функций-членов.

9 голосов
/ 13 августа 2011

Нет, это не имеет значения во время выполнения, это просто синтаксис.Указатель this по-прежнему доступен в первой функции, он указывается только неявно, а не явно.

Кстати, это пахнет преждевременной оптимизацией - сначала пишите чистый код, потом - быстрый код.

6 голосов
/ 13 августа 2011

Синтаксис 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 голосов
/ 13 августа 2011

То же самое.Тем не менее, «это» может быть использовано для устранения неоднозначности в некоторых случаях.

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;
};
3 голосов
/ 13 августа 2011

Нет, разницы нет.
Когда вы ссылаетесь на элемент напрямую, компилятор фактически разыменовывает его через this.

2 голосов
/ 13 августа 2011

То, что вы можете сказать foo вместо this->foo - это просто синтаксический сахар. Нет разницы в скомпилированном коде. Как и весь синтаксический сахар, маленькая горстка осуждает его, но большинство любит его. Чтобы увидеть, где вы стоите в этом вопросе, попробуйте использовать такой язык, как perl или python, который не предоставляет этот синтаксический сахар. Код Python дополняется self.foo; в OO-коде perl вы увидите self->foo повсюду. Это может немного отвлекать.

2 голосов
/ 13 августа 2011

Нет разницы, компилятор уже автоматически генерирует код для этого-> Хотя это излишний синтаксис, есть две веские причины для его использования:

  • с использованием редактора, который поддерживает автозавершение.Когда вы набираете «this->», редактор открывает окно инструментов, в котором представлен список членов класса на выбор.Это может ускорить ввод и помогает избежать глупых ошибок компиляции из-за ошибок ввода.

  • помогает избежать необходимости придумывать искусственные имена аргументов.Вы можете дать аргументу то же имя, что и у члена класса: void set_x (int x) {this-> x = x;}.

2 голосов
/ 13 августа 2011

Нет.

Если вы наткнулись на это выражение в чьем-то коде, оно, вероятно, возникло примерно так:

struct A
{
    int x;

    void set_X(int x)
    {
        this->x = x;
    }
};
1 голос
/ 13 августа 2011

Один из случаев, когда это имеет значение, это когда вы назначаете локальной переменной то же имя, что и у члена класса.Например:

class Example {

public:

    int something();
    int somethingElse();

}


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