2

This question came in my mind due to the following error in my c++ program

#include <iostream>
using namespace std;
class Test
{
private:
  int x;
public:
  Test(int x = 0) { this->x = x; }
  void change(Test *t) { this = t; }
  void print() { cout << "x = " << x << endl; }
};

int main()
{
  Test obj(15);
  Test *ptr = new Test (100);
  obj.change(ptr);
  obj.print();
  return 0;
}

Error:

main.cpp:18:31: error: lvalue required as left operand of assignment
   18 | void change(Test *t) { this = t; }
      |    

I searched about this error and found that it generally occurs when we try to assign the constants on the left hand side of the assignment operators to the variable on the right hand side.

Russia Must Remove Putin
  • 374,368
  • 89
  • 403
  • 331
  • `this = t;` I wonder if this is allowed. – kiner_shah Dec 04 '21 at 05:52
  • Hmm.... I suppose the following are not duplicates because they ask how to get around this, while the current question asks why this happens (even though the answer to "why" comes up in the answers to the other questions): [Cannot assign to this](https://stackoverflow.com/questions/15333134/) and [Can not assign to this: lvalue required as left operand of assignment](https://stackoverflow.com/questions/20083516/) – JaMiT Dec 04 '21 at 07:15
  • Assigning to `this` is not allowed. Back in the olden days it was, and that was the mechanism for dynamic allocation: the constructor would check whether `this` was null, and if it was, it would allocate memory for the object and assign the address of that memory to `this`. Fortunately, we have `operator new` now, so don't have to deal with that kind of thing any more. – Pete Becker Dec 04 '21 at 13:33

3 Answers3

0

From cppreference this:

The keyword this is a prvalue expression whose value is the address of the implicit object parameter (object on which the non-static member function is being called).

You can't assign to rvalues(e.g. 1 = obj is invalid). So, you'd have to dereference this and assign.

*this = *t;

To answer the title of the question,

this keyword used in class and objects is a constant pointer?

No, it is not. Even if a member function is marked const then it's still a pointer to const object.

From cppereference,

The type of this in a member function of class X is X* (pointer to X). If the member function is cv-qualified, the type of this is cv X* (pointer to identically cv-qualified X).

Ch3steR
  • 20,090
  • 4
  • 28
  • 58
0

According to 9.3.2 The this pointer [class.this]

1 In the body of a non-static (9.3) member function, the keyword this is a prvalue expression whose value is the address of the object for which the function is called. [...]

So as the error says, the left hand side should be an lvalue but you're giving it a prvalue because change is a non-static member function and inside any non-static member function the keyword this is a prvalue according to the above quoted statement. Hence the error.

But you can modify the object that this points to, as shown below:

#include <iostream>
using namespace std;
class Test
{
private:
  int x;
public:
  Test(int x = 0) { this->x = x; }
  void change(Test *t) { *this = *t; }//THIS WORKS 
  void print() { cout << "x = " << x << endl; }
};

int main()
{
  Test obj(15);
  Test *ptr = new Test (100);
  obj.change(ptr);
  obj.print();
  return 0;
}

Note in the above example i have replaced this = t; with

*this = *t;//this time it works because now the left hand side is an lvalue 

This time the program works because now the left hand side is an lvalue.

Some More Explanation

From IBM's this pointer documentation,

The this parameter has the type Test *const. That is, it is a constant pointer to a Test object. Now since it is constant pointer, you cannot assign a different pointer value to it using this = t;. And hence the error.

Similarly, from Microsoft's this pointer documentation,

the this pointer is always a const pointer. It can't be reassigned.

So this also explains the error you're getting.

Jason
  • 36,170
  • 5
  • 26
  • 60
  • From the [standard](https://timsong-cpp.github.io/cppwp/n4140/class.this), you linked: *The type of `this` in a member function of a `class X` is `X*`. If the member function is declared `const`, the type of `this` is `const X*`*. I am not really sure if IBM's documentation is 100% wrong(maybe they are referring to different implementation) but the standard you linked says `this` is not a const pointer. I believe the standard is correct here([Link](https://godbolt.org/z/3vG3o57f6)). – Ch3steR Dec 04 '21 at 07:28
  • @Ch3steR From [here](https://learn.microsoft.com/en-us/cpp/cpp/this-pointer?view=msvc-170) : **the `this` pointer is always a const pointer. It can't be reassigned.** – Jason Dec 04 '21 at 09:06
  • Yes, but those are implementation specifics not what the standard states. Not saying what you posted is wrong but since you opened with the answer with a link to standard and put links from IBM and Microsoft to state `this` is `const` even tho the standard you linked says "The type of this in a member function of a class X is X*. If the member function is declared const, the type of this is const X*". Each vendor can give their own implementation but standard clearly states `this` is non-const pointer. – Ch3steR Dec 04 '21 at 09:21
  • This is just like `GCC` supports VLA even tho the standard says C++ doesn't have VLA. Again not saying your answer is wrong. – Ch3steR Dec 04 '21 at 09:25
  • Please check out [Type of `this`](https://stackoverflow.com/a/6067267/12416453) Quoting the relevant parts "It is worth nothing that back in the C++98/C++03 times several compilers used an internal implementational trick: they interpreted their this pointers as constant pointers, e.g. ClassName *const in a non-constant method of class ClassName. MSVC++ still uses it (as of VS2017)"[1/2] – Ch3steR Dec 04 '21 at 09:30
  • [2/2] ..."Pointer this is not an lvalue, which means that it cannot possibly have ClassName * const type, i.e. it cannot possible have a const to the right of the *. Non-lvalues of pointer type cannot be const or non-const. There's simply no such concept in C++ language. What you observed must be an internal quirk of the specific compiler. Formally, it is incorrect.". Check [this comment the answerer(AnT) posted](https://stackoverflow.com/questions/6067244/type-of-this-pointer/6067267#comment7025581_6067263) – Ch3steR Dec 04 '21 at 09:31
  • @Ch3steR Yes since `this` is a **prvalue**, adding a top level const doesn't make sense. Note that many standard(commonly used) C++ books still teach `this` to be a constant pointer to a class Object. For example this is one quote from C++ primer by Stanley: **By default, the type of `this` is a const pointer to the nonconst version of the class type.** Hence the confusion. – Jason Dec 04 '21 at 09:47
  • Quote from [Bjanre's book](https://rads.stackoverflow.com/amzn/click/com/0321958322): "In a non- static member function, the keyword this is a pointer to the object for which the function was invoked. In a non- const member function of class X , the type of this is X∗ . Howev er, this is considered an rvalue, so it is not possible to take the address of this or to assign to this . In a const member function of class X , the type of this is const X∗ to prevent modification of the object itself." – Ch3steR Dec 04 '21 at 09:56
  • Instead of quoting from IBM, MSVC page the best bet(at least for standard C++) is to quote from the standard which you already did at the top of your answer but don't know why you choose to quote the type of `this` from compiler vendors rather choosing the standard. – Ch3steR Dec 04 '21 at 09:59
  • @Ch3steR Note that i have a separate section called *Some More Explanation* at the end of my answer.This(that `this` is a prvalue) is the reason why i added a separate section and started both the answers in that section with a link to the corresponding implementation.Similarly, the very first section of my answer starts with a link to the C++ standard and in this first section i did not mention anything about `Test *const` because the standard doesn't say that `this` is a `const` pointer. **I wanted to separate out this important point which is why i added 2 separate sections in my answer.** – Jason Dec 04 '21 at 10:00
0

In non-const member function, the type of this is "Type* const this" while it is "const Type* const this" in const member function. So you can't change a const this value to make it point to another address. you can use codes below to simulate it :

struct A{
    int a;
};
int main() {
      A* const p = new A();
      p = new A();    
      return 0;
}

you will get the same errorenter image description here

The following pictures shows the types of this in const member function and non-const member function: enter image description here

enter image description here

Keanyuan
  • 206
  • 1
  • 9
  • *"Type\* const this" while it is "const Type\* const this" in const member function* No, it's not. `this` is not const pointer. `std::is_const` with `this` returns `false`([Link](https://godbolt.org/z/nTWTvddqh)) – Ch3steR Dec 04 '21 at 06:24
  • @Ch3steR When I debug your codes, the vscode shows the type of this althrough the is_const return false! I append the pictures to my answer up. – Keanyuan Dec 04 '21 at 07:36
  • I don't know about VS code but SO post on type of `this` [Type of `this`](https://stackoverflow.com/q/6067244), [C++ is `this` pointer `const` pointer](https://stackoverflow.com/q/16102143) They claim `this` is non-const ptr. – Ch3steR Dec 04 '21 at 07:51
  • But one of above-linked questions says *I observed that the type of 'this' pointer is "ClassName * const this" on windows using VC++ 2008.* but the answer still claims "`this` is non-const. What you observed must be an internal quirk of the specific compiler." – Ch3steR Dec 04 '21 at 07:54
  • In const member functions, there are two features: 1. we can't change this value to point other address. 2. we can't change the values which the this point to. These satisfy features of the type of "const Type* const this". – Keanyuan Dec 04 '21 at 07:56
  • To answer points 1) `this` is prvalue is can never appear on left side. 2) That reason it's a pointer to const object. so `const type*` satisfy both the points you mentioned. – Ch3steR Dec 04 '21 at 08:08
  • 1
    I found the reason why you got `*const`: "It is worth nothing that back in the C++98/C++03 times several compilers used an internal implementational trick: they interpreted their this pointers as constant pointers, e.g. ClassName *const in a non-constant method of class ClassName. MSVC++ still uses it (as of VS2017), which prevents the above perfectly valid code from compiling in MSVC++."[source](https://stackoverflow.com/a/6067267) – Ch3steR Dec 04 '21 at 08:19
  • So, Its MSVC's implementation details. The standard clearly states 'The type of this in a member function of a class X is X*. If the member function is declared const, the type of this is const X*'[source](https://timsong-cpp.github.io/cppwp/n4140/class.this) – Ch3steR Dec 04 '21 at 08:23
  • @Ch3steR The pictures were captured on Linux with gcc compiler. Is this relate to compiler or IDE? – Keanyuan Dec 04 '21 at 10:49
  • VS Code install [C/C++ Microsoft's extension for IntelliSense, debugging and code browsing](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools). That maybe the reason but I'm not 100% sure. – Ch3steR Dec 04 '21 at 15:08