6

Say the object is

class A {
public :  void Silly(){
    this = 0x12341234;
}

I know I will get compiler error ' "this" is not a lvalue.' But then it is not a temporary either. So what is the hypothetical declaration of "this" ?

Compiler : GCC 4.2 compiler on mac.

Ajeet Ganga
  • 8,353
  • 10
  • 56
  • 79

5 Answers5

6

For some class X, this has the type X* this;, but you're not allowed to assign to it, so even though it doesn't actually have the type X *const this, it acts almost like it was as far as preventing assignment goes. Officially, it's a prvalue, which is the same category as something like an integer literal, so trying to assign to it is roughly equivalent to trying to assign a different value to 'a' or 10.

Note that in early C++, this was an lvalue -- assigning to this was allowed -- you did that to handle the memory allocation for an object, vaguely similar to overloading new and delete for the class (which wasn't supported yet at that time).

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
4

It is impossible to provide a "declaration" for this. There's no way to "declare" an rvalue in C++. And this is an rvalue, as you already know.

Lvalueness and rvalueness are the properties of expressions that produce these values, not the properties of declarations or objects. In that regard, one can even argue that it impossible to declare an lvalue either. You declare an object. Lvalue is what is produced when you use the name of that object as an expression. In that sense both "to declare an rvalue" and "to declare an lvalue" are oxymoron expressions.

Your question also seems to suggest that the properties of "being an lvalue" and "being a temporary" are somehow complementary, i.e. everything is supposedly an lvalue or a temporary. In reality, the property of "being a temporary" has no business being here. All expressions are either lvalues or rvalues. And this happens to be an rvalue.

Temporaries, on the other hand, can be perceived as rvalues or as lvalues, depending on how you access the temporary.

P.S. Note, BTW, that in C++ (as opposed to C) ordinary functions are lvalues.

fredoverflow
  • 256,549
  • 94
  • 388
  • 662
AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • Well, coming from C background I tend to see rvalue's declaration as "const lvalue-type" – Ajeet Ganga Sep 08 '11 at 00:00
  • @Ajeet: That's really strange. C language is not much different from C++ in this regard. In C language `const int` declaration declares an **lvalue**, not an rvalue. – AnT stands with Russia Sep 08 '11 at 00:06
  • While you can't declare an rvalue, you can (for example) declare/define an lvalue of a type to which that value can be assigned without a conversion. – Jerry Coffin Sep 08 '11 at 00:14
  • @AndreyT : Agree. Its just that my mental perception differentiates 'rvalue' which is a const 'lvalue', from true-'rvalue' which is temporaries that really do not have an address. The rvalue (const 'lvalue') do have an address. Its just that compiler builds firewalls around them. – Ajeet Ganga Sep 08 '11 at 00:38
  • @AndreyT : If functions were lvalue, shouldnt the function assignment be possible ? void f(){} void f1(){} main(){ f = f1; } Btw, this gives **funny** error " cannot convert 'int ()()' to 'int ()()' in assignment" – Ajeet Ganga Sep 08 '11 at 00:47
  • @Ajeet: Assignment? Lvalueness is no longer related to assignment in any direct way. "Lvalue" means "something residing in memory". Roughly, in C++ lvalue is something you can use as an operand of the built-in unary `&` operator (although bit-fields are also lvalues). Functions, arrays, const objects are examples of non-modifiable lvalues. – AnT stands with Russia Sep 08 '11 at 01:22
  • @AndreyT : Thanks for reminding me. :) Reminded me of second from C-FAQ-eskimo . "Functions, arrays, const objects are examples of non-modifiable lvalues." PS: C-FAQ-eskimo comparison with your comment is highest compliment from me. :) – Ajeet Ganga Sep 08 '11 at 12:00
3

For one thing, this is not a variable - it's a keyword. When used as a rvalue, its type is A * or A const *. In modern C++, assigning to this is prohibited. You cannot take the address of this, either. In other words, it's not a valid lvalue.

Seva Alekseyev
  • 59,826
  • 25
  • 160
  • 281
  • 2
    "*When used as a rvalue, its type is `A *` or `A * const`.*" You mean `A *` or `A const *`. – ildjarn Sep 07 '11 at 23:38
  • 2
    @Seva: There's a simple rule that helps keep it clear. If you look at a declaration like `T * p;`, `T` is the target type and `p` is the name of the pointer itself, with the `*` as kind of a "wall" between the two. If you put `const` (or `volatile`) on the pointer side of the wall, it affects the pointer. If you put it on the "type" side of the wall, it affects the type the pointer is pointing at. – Jerry Coffin Sep 07 '11 at 23:59
2

To answer the second part, "why is this not an lvalue", I'm speculating as to the committee's actual motivation, but advantages include:

  1. assigning to this doesn't make much logical sense, so there's no particular need for it to appear on the left-hand-side of assignments. Making it an rvalue emphasises that this doesn't make much sense by forbidding it, and means that the standard doesn't have to define what happens if you do it.
  2. making it an rvalue prevents you taking a pointer to it, which in turn relieves the implementation of any need to furnish it with an address, just like a register-modified automatic variable. It could for example devote a register in non-static member functions to storing this. If you take a const reference, then unless the use permits cunning optimization it needs to be copied somewhere that has an address, but at least it needn't be the same address if you do it twice in quick succession, as it would need to be if this were a declared variable.
Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
  • To see the proof in pudding, I was playing with this : const int i = 10; * ( int * )((void*)&i) = 20; Which is valid. But I can not do so with 'this' as I can not apply & to 'this'. – Ajeet Ganga Sep 08 '11 at 00:43
  • 1
    Yes, although IIRC the standard doesn't actually define "valid program" or "valid code". Your code is well-formed but has undefined behavior, some people seem to call that "not valid". Your point stands, though: it's a stupid thing that you can do with a const lvalue, but can't so easily do with an rvalue. A similar trick that does work with `this` is `template T& stupid(const T &r) { return const_cast(r); }` followed by `stupid(this) = 0;`. Not recommended. – Steve Jessop Sep 08 '11 at 01:16
  • +1 Hmm, so templates is something that is yet to be made foolproof then. :) – Ajeet Ganga Sep 08 '11 at 11:51
  • @Ajeet: to a sufficiently talented fool. – Steve Jessop Sep 08 '11 at 12:08
  • Ohh, I wouldnt use that in production, but surely to test my perception of world beyond obvious. :) – Ajeet Ganga Sep 08 '11 at 12:49
1

You get a compiler error because this is a const pointer to the instance of the class of the same type as that class. You can't assign to it although you can use it to change other class members in non-const qualified methods, call methods, and operators. Also note because it's an instance that static methods do not have a this pointer.

Hypothetical:

class Whatever
{
    // your error because this is Whatever* const this;
    void DoWhatever(const Whatever& obj) { this = &obj; } 

    // this is ok
    void DoWhatever(const Whatever& obj) { *this = obj; }

    // error because this is now: const Whatever* const this;
    void DoWhatever(const Whatever& obj) const { *this = obj; } 

    // error because this doesn't exist in this scope
    static void DoWhatever(const Whatever& obj) { *this = obj; }
};
AJG85
  • 15,849
  • 13
  • 42
  • 50