B-Mac
B-Mac

Reputation: 567

Why can't the 'this' pointer be used in the constructor initializer list?

I mean, we can't do:

class A {
    int i;
    char c;
public:
    A(int i = 0, char c = ' ') : this->i(i), this->c(c) {}
};

Is it because the instance hasn't been created yet or something like that?

Upvotes: 2

Views: 208

Answers (4)

Andreas DM
Andreas DM

Reputation: 10998

It is because the this pointer needs to be inside one of the following:

cppreference:

It can appear in the following contexts:
1) Within the body of any non-static member function, including member initializer list
2) within the declaration of a non-static member function anywhere after the (optional) cv-qualifier sequence, including dynamic exception specification(deprecated), noexcept specification(C++11), and the trailing return type(since C++11)
3) within brace-or-equal initializer of a non-static data member (since C++11)

class Foo {
    int a[sizeof(*this)]; // error, not inside a member function
};

Similarly:

class A {
    int i = sizeof(*this); // valid - brace-or-equal initializer
    char c;
public:
    // Error, not inside member function.
    A(int i = 0, char c = ' ') : this->i(i), this->c(c) // invalid
    {}
};

When put inside of the body of the constructor, it will work:

A(int i = 0, char c = ' ')
{
    this->c = c; // 'this->' required for disambiguation
    this->i = i;
}

A(int i = 0, char c = ' ') : i(sizeof(*this)) // also valid
{}

It is often not necessary to use this-> explicitly.

Upvotes: 0

Galik
Galik

Reputation: 48615

You don't need to use this like that:

class A {
    int i;
    char c;
public:
    A(int i = 0, char c = ' ') : i(i), c(c) {} // syntax makes this good
};

That is totally fine and works exactly how you want it to work.

The syntax rules mean that parameters can not appear as the variable being initialized, only its parameter. So the compiler must resolve the variables outside the parens i() as the class member and the one inside the parens (i) from the parameters because they hide the member variables due to scoping rules.

A(int i = 0): i(i) {}
              ^       - syntax says that i must be a member 

A(int i = 0): i(i) {}
                ^     - syntax says normal scoping rules apply

Outside the parens it must be a class member but inside the parens the scoping rules are like in the constructor body - the parameters hide the member variables.

So it is a perfectly safe pattern to use to name your parameters the same as your data members.

Upvotes: 0

phantom
phantom

Reputation: 3342

You don't need the this keyword in the initializer list as anything in the initializer list must be declared within the class. When you do

class MyClass
{
    int member;
public:
    MyClass(int member) : member(member) { }
                          ^^^^^ Can only be resolved to a member of MyClass
}

member in the initializer list is not permitted to refer to anything other than int member within the class. Therefore the this keyword is unnecessary and would add additional parsing difficulties if compilers had to support both member(member) and this->member(member) within initializer list. While giving the impression that it is possible to initialize non-member variables within the initializer list at the same time.

Upvotes: 2

Overv
Overv

Reputation: 8529

If you look at an overview of the C++ grammar, specifically the mem-initializer-list section, you see that the initializer list should consist of identifier(expression) or classname(expression) entries. An identifier is defined here as string of digits and nondigits (a-z, A-Z, _).

Your this->identifier(expression) doesn't match that, so it's not allowed. It's not necessary anyway, because there is no ambiguity here. The identifier is always a member variable of the class, so it's clear which i is referred to.

class A {
    int i;
    char c;
public:
    A(int i = 0, char c = ' ') : i(i), c(c) {}
};

Upvotes: 1

Related Questions