Methodenaufrufe, ohne dass zuvor ein Obj angelegt wird.
-
hustbaer schrieb:
Ich denke nicht an Speicher der nicht mir gehört. Ich denke an sowas: ...
Nicht ganz das, was der Threadersteller macht

Aber so, hmmmm ...
Theoretisch, wäre sowas ja nichts anderes als:char arr[sizeof(int)]; int* p = reinterpret_cast<int*>(&arr[0]); *p = 10;Und sowas ist doch erlaubt? Daher wäre es wahrscheinlich erlaubt ...
Ich würde es aber trotzdem über ein Placement New machen
Grüssli
-
Gestützt auf §3.8 würde ich sagen, dass es bei einem POD reicht den Speicher zu reservieren und das Objekt ist gültig, daher ist der Funktionsaufruf auch kein UB. Für einen "non-POD class type" wird der Aufruf einer nicht-statischen Funktion ja explizit als UB definiert (auch §3.8).
Aber helft mir mal kurz.
Wenn ich, wie der Threadstarter, einen mit 0 initialisierten Zeiger nehme und über diesen eine nicht-statische Funktion aufrufe die selbst keine illegalen Speicherzugriffe tätigt, wo sagt mir der Standard, dass das UB ist?
Von der Anschauung her würde ich sagen, dass das klappen müsste, schließlich ist es dem Funktionsaufruf selbst ja egal ob der übergebene this-Zeiger auf gültigen Speicher zeigt oder nicht, solange er nicht dereferenziert werden muss.
Ist die Funktion virtuell, dann ist Ende, das ist klar, aber was übersehe ich da bei einem normalen Funktionsaufruf bzw. wo ist die entsprechende Stelle im Standard?
Nicht dass ich irgendetwas in der Richtung implementiert habe, nur aus Interesse.

P.S.:
hustbaer schrieb:
Bzw. die noch bessere Frage ist eigentlich: ... formaljuristisch korrekter Ausdruck ...
So hab ich's gemeint. :p

-
Gut, ich helfe dir mal. Ich habe mal "kurz" im Standard gelesen und bin dabei auf das hier gestosssen. Ich glaube das definiert das Problem

Standard ISO IEC 14882:2003 schrieb:
5.2.5 Class member access
1 A postfix expression followed by a dot . or an arrow ->, optionally followed by the keyword template
(14.8.1), and then followed by an id-expression, is a postfix expression. The postfix expression before the
dot or arrow is evaluated; the result of that evaluation, together with the id-expression, determine the
result of the entire postfix expression.2 For the first option (dot) the type of the first expression (the object expression) shall be “class object” (of a
complete type). For the second option (arrow) the type of the first expression (the pointer expression) shall
be “pointer to class object” (of a complete type). In these cases, the id-expression shall name a member of
the class or of one of its base classes. [Note: because the name of a class is inserted in its class scope
(clause 9), the name of a class is also considered a nested member of that class. ] [Note: 3.4.5 describes
how names are looked up after the . and -> operators. ]3 If E1 has the type “pointer to class X,” then the expression E1->E2 is converted to the equivalent form
(*(E1)).E2; the remainder of 5.2.5 will address only the first option (dot). Abbreviating object-
expression.id-expression as E1.E2, then the type and lvalue properties of this expression are determined as
follows. In the remainder of 5.2.5, cq represents either const or the absence of const; vq represents
either volatile or the absence of volatile. cv represents an arbitrary set of cv-qualifiers, as defined
in 3.9.3.Somit muss also das Objekt gültig sein und beim Zugriff über einen Zeiger wird dieser zuerst dereferenziert. Das dereferenzieren einer ungültigen Speicheradresse ist undefiniert.
Oder habe ich da einen Denkfehler gemacht?

Grüssli
-
Dravere schrieb:
Gut, ich helfe dir mal.
Das ist aber nett. Vielen Dank.

Fazit: Besser gleich auf Tippgeber gehört, der da meinte es hat keinen Sinn darüber zu diskutieren und Recht hatte er.

-
@Dravere:
Die Stelle sagt IMO über das hier Diskutierte nichts aus.Ich denke du misverstehst den Begriff "complete type".
Complete Type bedeutet dass ein Typ (Klasse) definiert ist, und nicht nur deklariert:struct A; // <- A ist "incomplete" hier struct A { int i; }; // <- hier ist A jetzt ein "complete type"
-
Jap, hab grad nochmals nachgelesen, "complete type" bedeutet hier was anders. Aber was ist mit Abschnitt 3? Ein Aufruf der Form
p->methode()wird umgewandelt zu(*(p)).methode(). Eine Dereferenzierung vonp, wennpauf 0 oder einem Speicherbereich zeigt, welcher einem nicht gehört, führ doch zu UB.
Oder versteh ich das auch falsch? ...Grüssli
-
Ihr habt doch hier zwei unterschiedliche Situationen. Eine, in der das Objekt gültig ist, und eine, in der das Objekt nicht gültig ist. Dabei dürfte doch völlig egal sein, ob das Objekt POD oder nicht POD ist. Nur, dass bei PODs das Objekt bereits gültig ist, sobald der Speicher reserviert wurde.
NonPodType* npt = 0; npt->feld = 10; // UB npt->methode(); // UB PodType* pt = 0xdeadbeef; pt->feld = 10; // UB pt->methode(); // UB NonPodType* npt2 = new NonPodType(); npt2->feld = 10; // ok npt2->methode(); // ok PodType* pt2 = (PodType*) malloc(sizeof(PodType)); // man verzeihe mir das C-gefrickel pt2->feld = 10; // ok pt2->methode(); // ok
-
@LordJaxom: richtig.
-
LordJaxom schrieb:
Ihr habt doch hier zwei unterschiedliche Situationen. Eine, in der das Objekt gültig ist, und eine, in der das Objekt nicht gültig ist. Dabei dürfte doch völlig egal sein, ob das Objekt POD oder nicht POD ist. Nur, dass bei PODs das Objekt bereits gültig ist, sobald der Speicher reserviert wurde.
Ursprünglich gab es nur eine Situation und zwar wenn das Objekt noch nicht gültig sei. Mitleid hat in diesem Kontext dann auch nachgefragt, wie das bei PODs sei. Erst hustbaer hat da eine andere Situation reingebracht, welche etwas für Verwirrung sorgte

Aber so wie du es zusammengefasst hast, sehe ich das auch.
Grüssli
-
Auch richtig. Die andere Situation hab' ich reingebracht, weil die ursprüngliche Frage für mich ziemlich klar war.