this Zeiger
-
Der this Zeiger ist gar keine Variable, wie du fälschlicherweise annimmst. Deswegen bekommst du auch nicht die Fehlermeldung die du erwartest. Die Meldung, dass es sich nicht um einen lvalue handelt, bedeutet aber praktisch das gleiche: es ist kein Objekt dem man etwas zuweisen kann*.
*: Die betonung liegt hier auf "kann". Konstanten Variablen haben manchmal eine echte Speicheradresse (sofern nicht wegoptimiert). Man könnte ihnen theoretisch was zuweisen, der Compiler verhindert es aber. Der this-Zeiger ist gar kein Objekt, das man adressieren könnte, sondern einfach ein Schlüsselwort der Sprache das für "Adresse des aktuellen Objekts" steht.
-
thx @ SeppJ, das hilft mir weiter

-
Die betonung liegt hier auf "kann". Konstanten Variablen haben manchmal eine echte Speicheradresse (sofern nicht wegoptimiert). Man könnte ihnen theoretisch was zuweisen, der Compiler verhindert es aber. Der this-Zeiger ist gar kein Objekt, das man adressieren könnte, sondern einfach ein Schlüsselwort der Sprache das für "Adresse des aktuellen Objekts" steht.
Das ist falsch.
9.3.2 The this pointer [class.this]
1 In the body of a nonstatic (9.3) member function, the keyword this is a non-lvalue expression whose
value is the address of the object for which the function is called. 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*, if the member
function is declared volatile, the type of this is volatile X*, and if the member function is
declared const volatile, the type of this is const volatile X*.this ist also ein ganz normaler Zeiger vom Typ const T*. (je nachdem noch der der volatile Bezeichner.)
Somit verhält sich this, wie jeder andere const Zeiger ebenfalls.
-
drakon schrieb:
9.3.2 The this pointer [class.this]
1 In the body of a nonstatic (9.3) member function, the keyword this is a non-lvalue expression whose
value is the address of the object for which the function is called. 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*, if the member
function is declared volatile, the type of this is volatile X*, and if the member function is
declared const volatile, the type of this is const volatile X*.this ist also ein ganz normaler Zeiger vom Typ const T*. (je nachdem noch der der volatile Bezeichner.)
Somit verhält sich this, wie jeder andere const Zeiger ebenfalls.
In deiner zitierten Textstelle steht aber was ganz anderes?

Außerdem beschreibt "const T*" den Typ eines (veränderlichen) Zeigers auf ein konstantes T und nicht den Typ eines konstanter Zeigers auf ein (veränderliches) T.
-
Hmm. Ich hab da jetzt übereilig da was hingeschrieben. Wenn überhaupt müsste ja der Zeiger const sein. (Das andere ist natürlich klar, wenn das Objekt const ist, dann ist, dann zeigt auch der Zeiger auf ein Konstates Objekt). Aber ich hatte wirklich im Kopf, dass this vom Typ T *const ist.. Das verwirrt mich jetzt doch ein bisschen. Macht ja keinen Sinn this etwas zuweisen zu wollen..
-
drakon schrieb:
9.3.2 The this pointer [class.this]
1 In the body of a nonstatic (9.3) member function, the keyword this is a non-lvalue expression whose
value is the address of the object for which the function is called. 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*, if the member
function is declared volatile, the type of this is volatile X*, and if the member function is
declared const volatile, the type of this is const volatile X*.this ist also ein ganz normaler Zeiger vom Typ const T*. (je nachdem noch der der volatile Bezeichner.)
Somit verhält sich this, wie jeder andere const Zeiger ebenfalls.
Also den Text aus dem aktuellen Draft des Standards kann ich nur bestätigen, hab' da mal reingesehen, und Drakon's Post ist mit diesem Inhaltsgleich.
Mein Visual Studio zeigt mir für 'this' auch bei folgender Klasse die in dem Text beschriebenen Datentypen an, somit wurde es dort auch so implementiert:
class CThis { public: int i; void CV-Unqualified(void) { int a = this->i; // CThis *const this // Konstanter Zeiger (rvalue) auf CThis }; void C-Qualified(void) const { int a = this->i; // const CThis *const this // Konstanter Zeiger (rvalue) auf konstantes CThis }; void V-Qualified(void) volatile { int a = this->i; // volatile CThis *const this // Konstanter Zeiger (rvalue) auf volatile CThis }; void CV-Qualified(void) const volatile { int a = this->i; // volatile const CThis *const this // Konstanter Zeiger (rvalue) auf konstantes volatile CThis }; CThis(){}; ~CThis(){}; };In jedem der Fälle handelt es sich, wie wieder im Std gut beschrieben, um einen non-lvlaue (also ein rvalue), dem ja sowieso nichts zuweisbar ist. Somit, finde ich, passt die Fehlermeldung die DWeb bekommt allemal.
Gruß
PuerNoctis
-
Ja, passen tuts allemal. Mich wundert einfach nur, dass der Zeiger per Standard nicht const sein muss. (non-lvalue verhindert natürlich Zuweisung, aber ich finds trotzdem ein wenig komisch..)
-
Hm, vielleicht hat Microsoft das so implementiert, dass ein non-lvalue im VC nur durch ein const-Verhalten überhaupt existieren kann. Somit würde sich das T*const wohl eher durch den Compiler ergeben, und muss nicht durch den Standard definiert sein. Hab' das jetzt leider nicht mit dem GCC geprüft oder anderen Compilern, ob das bei denen auch T*const ist.
Könnte mir aber wirklich gut vorstellen, dass dem Std egal ist WIE der rvalue entsteht, Hauptsache er ist einer^^. Wäre für mich zumindet eine logische Erklärung...
Gruß
PuerNoctis
-
Oh mein Gott, folgendes funktioniert:
#include <iostream> class CThis { public: int i; void Umbiegen(void) { CThis Other; Other.i = 666; (const_cast<CThis*>(this)) = &Other; std::cout << this->i; }; CThis() : i(0){}; ~CThis(){}; }; int main(int argc, char** argv) { CThis Test; Test.Umbiegen(); return 0; }Ausgabe:
666
-
PuerNoctis schrieb:
Hm, vielleicht hat Microsoft das so implementiert, dass ein non-lvalue im VC nur durch ein const-Verhalten überhaupt existieren kann.
Dann würde
struct foo { void bar() {} }; int main() { foo().bar(); }Ja gar nicht gehen (weil bar non-const und non-lvalue). Oder hab ich dich falsch verstanden?
Bei GCC ist this übrigens kein rvalue, was sich einfach dadurch beweisen lässt, dass folgendes kompiliert:
template<typename T> void test(T&){} struct foo { void bar() { test(this); } };Mit richtigen rvalues kompiliert das nicht. (z.B. test(foo()))
-
Du rufst da einfach eine Funktion auf ein tempotäres Objekt auf.
-
Ryuzaki schrieb:
Bei GCC ist this übrigens kein rvalue, was sich einfach dadurch beweisen lässt, dass folgendes kompiliert:
template<typename T> void test(T&){} struct foo { void bar() { test(this); } };Mit richtigen rvalues kompiliert das nicht. (z.B. test(foo()))
Ich fürchte (drakon bestätigend), in T steckt am ende genug const, daß ein temoptäres Objekt gebaut wird.
#include <iostream> using namespace std; struct foo { static void test(foo*const& th) { } void bar() { test(this+1); } }; int main() { foo f; f.bar(); }
-
Skalare rvalues sind niemals cv-qualifiziert und zwar einfach deshalb, weil es handelt sich nicht um Objekte handelt, d.h. Speicherbereiche, deren Inhalt man sich als änderbar vorstellen könnte. (3.10/9)