开发者

Does it matter if this is used in a C++ setter?

Suppose I have a c++ class with a private variable, x. Fo开发者_Go百科r it's setter, is there any difference using this? Is there the potential for unwanted / unexpected behavior is I don't use this?

Setter:

void setX(double input)
{
   x = input;
}

Setter using this:

void setX(double x)
{
   this->x = x;
}


These two code fragments (assuming they're inline member functions, since there's no ClassName:: bit) are exactly equivalent. Use whichever you prefer. I would tend to recommend against naming parameters the same as member variables though; it's too easy get them mixed up.


Because of two-phase lookup for class templates, this might be required to

  1. explicitly state you mean a member
  2. because of lookup rules, the compiler might assume another entity that is visible there is meant

(see the first example) Both are equivalent.

In a non-template situation, you usually avoid using this; the generated code will be the same, thus there won't be any difference (see the second example). The reason for this is that the compiler will try to lookup every symbol it sees. The first place to lookup is in class-scope (except for block and function scope). If it finds a symbol of that name there, it will emit this implicitly. In reality, member functions are just ordinary functions with an invisible parameter.

class Foo {
    void foo () { x = 0; }
    void bar () const { std::cout << x; }
    void frob();
    int x;
};
void Foo::frob() {}

Is actually transformed into

class Foo {        
    int x;
};
inline void foo (Foo *const this) { this->x = 0; }
inline void bar (Foo const * const this) { std::cout << this->x; }
void frob (Foo * const this) {}

by the compiler.


Behavioral example for this in templates:

#include <iostream>

void foo() {
    std::cout << "::foo()\n";
}

template <typename>
struct Base {
    void foo() const { std::cout << "Base<T>::foo()\n"; }
};

template <typename T>
struct Derived_using_this : Base<Derived_using_this<T> > {
    void bar() const { this->foo(); }
};

template <typename T>
struct Derived_not_using_this : Base<Derived_not_using_this<T> > {
    void bar() const { foo(); }
};


int main () {
    Derived_not_using_this<void>().bar();
    Derived_using_this<void>().bar();
}

Output:

::foo()
Base<T>::foo()

Example assembly for non-template:

With this:

pushq   %rbp
movq    %rsp, %rbp
subq    $16, %rsp
movq    %rdi, -8(%rbp)
movq    -8(%rbp), %rax
movl    (%rax), %eax
movl    %eax, %esi
movl    $.LC0, %edi
movl    $0, %eax
call    printf
leave
ret

Without this:

pushq   %rbp
movq    %rsp, %rbp
subq    $16, %rsp
movq    %rdi, -8(%rbp)
movq    -8(%rbp), %rax
movl    (%rax), %eax
movl    %eax, %esi
movl    $.LC0, %edi
movl    $0, %eax
call    printf
leave
ret

Verify yourself:

test.cc:

#include <stdio.h> // Don't use this. I just did so for nicer assembly.

class Foo {
public:
    Foo () : i(0) {}

    void with_this() const { printf ("%d", this->i); }
    void without_this() const { printf ("%d", i); }
private:
    int i;
};


int main () {
    Foo f;
    f.with_this();
    f.without_this();
}

Run g++ -S test.cc. You'll see a file named test.s, there you can search for the function names.


The this variant makes a syntactical difference when templates are involved. However, it is semantically the same; the this-> variant just makes it clearer you are accessing the current objects and avoids potential collisions.


void setX(double x)
{
    this->x = x;
}

If the member variable x would be obscured by the argument x, then this-> is explicitly needed to ensure you are assigning to the correct variable. Otherwise it is not needed.

But I don't recommend you name your argument the same thing as a member variable anyway. The first example you give has fewer pitfalls.


There is no difference between them.


Although your code will work, it is poor code and likely to confuse somebody.

Much better to give the "setX()" parameter a different name.

e.g.

void setX(double new_x)
{
   x = new_x;
}


Doesn't matter. I've worked with code conventions stating that all private vars should be accessed through this in order to make the code more readable. But other than readability I don't think there is any difference.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜