Why some people use "this->" when there is no need?

Pages: 123
I'm baffled that you think that's any better.
Lmao! If the issue is readability for other people looking at the code, simple comment will erase any confusion:

//variables one to three go to member variables in the order they're declared

I don't see how finding synonyms or making names longer (Ex: var becomes var_1) is much better. You still have to match the names with the variables.

With my method, you would *never* need to check the parameter list for the variable names to assign, you'd always know this format:

1
2
firstVar = one;
secondVar = two;
Last edited on
A lot of times people have variables in their function parameters with the same name as a variable in the class itself, and so using this-> becomes the only way to differentiate.


That's why class variables should be prefixed with "m", and it becomes self explanatory.

1
2
3
4
void classname::setvar( type var)
{
      mVar = var;
}


A lot of such issues can be avoided by simply including some sort of "CODING_STYLE.md" in your project, which should help newcomers adapt to codebase and writing style.

Using this->function(); just because there may be non class function with same name can also be avoided if your "CODING_STYLE.md" clearly states something like:

Before renaming class methods please make ensure there is no global symbol with same name by using search function first before using search\replace.
I wasn't sure whether or not to expect bar() to call the global function or the inherited one, but I was leaning towards inherited.

this-> is needed in that situation, but simply having the same function names at all makes it confusing.
Yeah - it displays:


bar()
Base::bar()


This is the sort of code that makes you want to perform certain anatomical procedures on the person who coded it...


@Gary the Monkey's code is a brilliant example, but I don't fully understand it.

If I remove all the template-related stuff from it then I obtain as output:
Base::bar()
Base::bar()


On the other hand, if I leave the template stuff in but delete the global bar() then it won't compile.

Somebody put me out of my misery and explain why the template-ing makes a difference.
Last edited on
It's all to do with the order used for function overload resolution. Put a wet towel around your head, have a large whiskey and read https://en.cppreference.com/w/cpp/language/overload_resolution

Which bit of that document explains why if I delete the global bar() then it won't compile?
Now I'm horified!

If I run Gary's code on cpp.sh or with the g++ compiler on my PC then it produces
bar()
Base::bar()


But if I run it with the Intel compiler (cl.exe) on my PC then it produces
Base::bar()
Base::bar()


I'm flummoxed.
Well as my post above, with MS VS it produces


bar()
Base::bar()


What version of Intel compiler are you using and for which C++ standard? I seem to remember some changes in overload resolution between versions?
@Gary the Monkey

I must admit this is another good example, but is an example of where one does need to use this as opposed to using this when there is no need.

I must also admit I'll go ahead and refresh my knowledge about overload resolution because I vouch for not using this yet don't know all cases when it must be used :/

learned something new
Well, here's a variant of @Gary the Monkey's code that doesn't call the global bar.
See the Edit at the bottom for why the using Base<T>::bar; statement is necessary.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>

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

template <typename T> class Base
{
  public:
    void bar() { std::cout << "Base::bar()\n"; }
};

template<typename T>
class Derived : Base<T>
{
  public:
    using Base<T>::bar;
    void foo() 
    {
        bar();
        this->bar();
    }
};
    
int main()
{ 
    Derived <int> d {};
    d.foo();
}


Base::bar()
Base::bar()




EDIT: found this on Stack Overflow https://stackoverflow.com/questions/24158209/accessing-base-member-functions-in-class-derived-from-template-class

When a class template derives from a base class template, the base members are not visible in the derived class template definition. (This makes sense; until you specialize, there is no class, and so there are no members. Explicit specializations can always change the meaning of any given template class.)

In other words, the base template member names are dependent names and not looked up in the first phase of template definition lookup.


See also https://stackoverflow.com/questions/4643074/why-do-i-have-to-access-template-base-class-members-through-the-this-pointer

That's quite a gotcha! Seems to be a "That's just how it is" decision with regards to look-up.
Last edited on
Yes - as in the above code there's a using on L18 which alters the overload resolution.

This is a reason why in templated code you often see statements like this:

 
template<class... Ts> struct overload : Ts... { using Ts::operator()...; };


Note that VS now does two-phase compilation.

PS Yes, the overload resolution was changed for C++17. See
https://devblogs.microsoft.com/cppblog/two-phase-name-lookup-support-comes-to-msvc/

There's an option to turn this on/off.

PPS. This seems to be a red herring. Compiling with permissive on and off both give the same result
Last edited on
simple comment will erase any confusion
x41 x39 x14 x31 x1 x20 x26 x22 x35 x34 x40 x3 x23 x8 x24 x4 x32 x7 x18 x13 x37 x21 x2 x36 x5 x17 x9 x8 x2 x33 x29 x8 x2 x11 x38 x6 x8 x2 x30 x12 x19 x43 x25 x2 x28 x27 x42 x15 x44 x16 x10

//Note: in the above text:
//x1 => "a"
//x2 => "the"
//x3 => "your"
//x4 => "worse"
//x5 => "are"
//x6 => "third"
//x7 => "that."
//x8 => "is"
//x9 => ""first"
//x10 => "elsewhere."
//x11 => "position,"
//x12 => "itself"),"
//x13 => "doesn't"
//x14 => "comments"
//x15 => "look"
//x16 => "that"
//x17 => "(e.g."
//x18 => "It"
//x19 => "it"
//x20 => "crutch."
//x21 => "what"
//x22 => "name"
//x23 => "comment"
//x24 => "even"
//x25 => "instructs"
//x26 => "Just"
//x27 => "to"
//x28 => "reader"
//x29 => "x1"
//x30 => "data"
//x31 => "as"
//x32 => "than"
//x33 => "size,"
//x34 => "properly."
//x35 => "things"
//x36 => "parameters"
//x37 => "explain"
//x38 => "and"
//x39 => "use"
//x40 => "Actually,"
//x41 => "Don't"
//x42 => "go"
//x43 => "just"
//x44 => "for"

Clear as day, right?
Last edited on
1
2
3
4
5
6
7
8
// a is assigned to alfa
// b is assigned to bravo
// c is assigned to charlie
void Foobar::Foobar(int a, int b, int c)
: alfa(a), bravo(b), charlie(c)
{

}

The problem is this code is that, first, it is not "self-documenting". A person calling the code sees that "a", "b", and "c" are parameters, but has no idea what they mean. Why force such confusion on the user? It's nonsensical. You're forcing the reader to exert more effort for the same end result. Second, comments aren't compiled. Comments aren't unit tested. The more you rely on comments, the more you'll see your code suddenly rot when somebody doesn't think to update them, or leaves an ambiguous comment.
I think writing good comments takes skills just as it takes to write good code.

doxygen become standard way to document code which a big step forward to unified way on how to write comments that are familiar.

I hope one day there will be some standard about coding style or at least no more than 3 styles that are widely used, it would help a lot for easier understanding when reading someone elses code.
> That's why class variables should be prefixed with "m", and it becomes self explanatory.
I hate prefix so I gonna write a prefix to avoid writing a prefix

> A lot of such issues can be avoided by simply including some sort of "CODING_STYLE.md" in your project,
this-> is not an issue

> Before renaming class methods please make ensure there is no global symbol with same name
¿why? the name is great, it conveys exactly what's needed
also, ¿what if later you #include "third_party.h" ?
¿are you going to rename your methods?
Clear as day, right?

So if you saw:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Test
{
    int size;
    int x, y;
    std::string name;
    double avg;
    char* p;

    Test(int a, int b, int c, std::string d, double e)
    {
        size = a;
        x = b;
        y = c;
        name = d;
        avg = e;

        p = nullptr;
    }
};



You'd actually be confused as to how the parameters and the member variables are related? I don't think it needs a comment to explain itself, but you could add a comment just in case.

The problem is this code is that, first, it is not "self-documenting".

In a way, that's true. Only as far as that the variable names aren't the same or almost the same.

But really, a constructor isn't complicated. It sets the values of the variables in the class. If you were to just look at which members are being set in there, why does it matter what the variable name is that you see on the other end of the = sign?
Why some people use "this->" when there is no need?

I can only speak for myself, but why I use this-> is for the same/similar reason(s) why I do NOT have using namespace std; littering my code. Using the std:: prefix and this-> "self"-documents my code.

I also use custom namespaces as much as possible when I want to use a name already used by the C++ standard or another commonly used library such as Boost.

I try as much as possible to use long-form descriptive names when creating variables, saving terse 1-3 letter names for loop counters.

I'm hot/cold on encoding variables, class or global, with prefixes. Globals more likely than class member data.

I mostly use comments as placeholders for code I have yet to write, or as reminders for testing of existing code. Rarely do I use them to document already written and properly working code.

Ultimately much of my code is For My Eyes Only. If'n I were working with others, and there was an established coding style, I'd bend and use what is already set.
So if you saw: [...] You'd actually be confused as to how the parameters and the member variables are related?
If I have to read the implementation to figure out the interface then the code is bad. I can, but I shouldn't have to. Just name things properly.
Pages: 123