Mal &, mal *
-
Ich weiß was Referenzen, Zeiger usw sind, aber ich bin noch nicht so drin.
Wir haben in den Vorlesungen immer Beispielcode, der mich ein wenig verwirrt.
Einmal ging es um das Thema pass-by-reference und die Methodensignatur sah ungefähr so aus:
void methode(int* value){ *value = 5; }Ist klar, der Aufruf der Methode sieht dann irgendwie so aus
int i = 6; methode(&i);Referenz gibt Adresse von i und Methode nimmt diese Adresse und behandelt das als Zeiger, was ich wundert, warum steht da noch *value = 5 ? Ändere ich so nicht den Pointer selbst (also die Adresse) und nicht den Wert des integers?
Später haben wir dann Copy Constructor gehabt, dort sieht der Kopf so aus:
Obj (Obj &r);Und der Aufruf
Obj o = Obj(andererObj);Ehm, warum wird mal Poiter genommen und Adresse übergeben und mal wird eine Referenz erwartet? Hat das was mit den komplexen Datentypen wie eigenen Klassen im Vergleich zu int,bool usw zutun? Würd ich pass-by-reference einer Variable vom Typ Obj die Methode oben auch so nutzen:
void methode(Obj &value)?
-
Technisch gesehen unterscheiden sich Referenzen und Zeiger nicht sehr weit, aber:
- Zeiger können auch als der Anfang eines Arrays angesehen werden (Adressarithmetik für Referenzen gibt's nicht)
- Zeiger können auch auf NULL verweisen
- Zeiger sind auch in C bekannt (wichtig für Bibliotheken, die aus C übernommen wurden)
-
Also läufts auf ein Mischmasch hinaus? Nichtwahr?
-
Seikilos schrieb:
...warum wird mal Poiter genommen und Adresse übergeben und mal wird eine Referenz erwartet? ...
Na - warum wird mal ein int, mal ein double mal ein string übergeben ?

C++ hat halt 2 "Typen von Verweisen": s. CStolls Erklärung.Seikilos schrieb:
...Hat das was mit den komplexen Datentypen wie eigenen Klassen im Vergleich zu int,bool usw zutun? ...
Nicht, dass ich wüsste (Evtl. gemeint: Call-by-value "kostet" bei komplexen Datentypen Performance ... aber für call-by-references, um die es hier geht, spielt das keine Rolle).
Seikilos schrieb:
...Würd ich pass-by-reference einer Variable vom Typ Obj die Methode oben auch so nutzen:
void methode(Obj &value)?
Jupp - Und aufgerufen via:
Obj myThing; methode(myThing);Seikilos schrieb:
Also läufts auf ein Mischmasch hinaus? Nichtwahr?

Genauso wie es mit int und string "auf ein Mischmasch hinaisläuft" : Man nimmt das, was passt.Gruß,
Simon2.
-
Hem, also was heißt mischmasch? Die zwei haben unterschiedliche Fähigkeiten und Überschneidungen darin. Aber im Prinzip kann man schon sagen, wann man was benutzt.
Pointer sind aber unerlässlich, wenn man C-Funktionen ansprechen will, weil C keine Referenzen kennt. Das dürfte der größte "Knackpunkt" sein.
-
Ok, jetzt ist es mir klar, ich war nur verwundert, weil bei CopyConstructor eine Referenz verwendet wurde und bei primitiven Datentypen Pointer und das wortlos, da kann man ja sonst was interpretieren, dass bei Constructoren dies geht, bei den anderen jenes.
Ist halt schlecht kommentiert
-
Ein anderes Beispiel aus der Operator Überladung.
Man hat eine Klasse Point und überlädt +=, nun steht da die MethodePoint Point::operator+=(Point &p){ // tu was return *this; }Ist das ein Fehler? Muss der Returnwert nicht *Point sein?
-
Und dein Beispiel oben:
void methode(int* value){ *value = 5; }könnte man auch mit einer Refernz machen! Dann spart man sich auch das sog. Dereferenzieren.
void foo(int& dest) { dest *= 5; }So kannst du sichergehen, dass dest kein NULL-Zeiger odg. ist, wie es bei der Zeiger-Variante sein könnte usw.
-
So wäre es optimal:
Point& Point::operator+=(const Point &p){ // tu was return *this; }Einen Pointer kannste nicht zurück geben, weil dann sowas nicht funktioineren würde:
Point p = p1 + p2 + p3;Wenn du einen Pointer zurück geben würdest, müsste p und p1 auch ein Pointer sein. Wäre ziemlich umständlich...

-
Am besten folgenden Satz merken:
Referenzen sind Aliasnamen für bestehende Variablen.Das ist bei Pointern nicht so. Pointer sind eigene Variablen die eine Adresse auf eine bestehende Variable speichern. Also insgesamt alles umständlicher.
int a = 0; int &r = a; // r ist a!!! int *p = &a; // p ist nicht a! Es zeigt auf a!
-
Seikilos schrieb:
...Muss der Returnwert nicht *Point sein?
*Point ist kein Typ.
"this" hat (ziemlich sicher in diesem Beispiel) den Typ "Point*" (Also: Zeiger auf Point).
"*this" hat also den Typ "Point".Ergo: Alles OK.
Gruß,
Simon2.
-
ich finds auch etwas komisch, dass man da zwei verschiedene Methoden für die gleiche sache verwenden kann, und damit ordendlich chaos erstellen kann.
Seikilos schrieb:
Einmal ging es um das Thema pass-by-reference und die Methodensignatur sah ungefähr so aus:
void methode(int* value){ *value = 5; }Ist klar, der Aufruf der Methode sieht dann irgendwie so aus
int i = 6; methode(&i);das ist übrigens call by value, denn der Datentyp ist int*, und die methode bekommt eine Kopie von dem Pointer
. Übrigens kann man in C++ auch referenzen auf pointer verteilen
.
-
Ja, aber ändern tu ich doch den Wert des ints, oder?
-
Jap, wie gesagt der Zeiger wird ja per Call-by-Value übergeben, den kannst du folglich garnicht ändern (nur die interne Kopie). Das, worauf er zeigt, kannst du natürlich verändern (und tust du auch in dem Beispiel).
Gruß
Don06
-
@Seikilos: Probier mal:
void new_array(int* arr, std::size_t size) { delete [] arr; arr = new int[size]; } int main() { int* arr = new int[10]; new_array(arr, 11); }...
-
Was bitte soll ich bezüglich dieses Codes probieren?
-
Hmm geh mal mitm debugger durch und vergleich arr vor und nach dem Funktionsaufurf ...
-
Seikilos schrieb:
Was bitte soll ich bezüglich dieses Codes probieren?
ich glaub er möchte, das du feststellst, das das so nicht funktioniert, wie es soll, denn die Adresse des von new_array erstellten arrays ist mit dem ende der Methode verloren, weil der Pointer selbst nur als kopie übergeben wurde, also änderungen an diesem haben keinerlei auswirkungen auf das Original.
-
Krux schrieb:
...
Seikilos schrieb:
Einmal ging es um das Thema pass-by-reference und die Methodensignatur sah ungefähr so aus:
void methode(int* value){ *value = 5; }...
Don06 schrieb:
Jap, wie gesagt der Zeiger wird ja per Call-by-Value übergeben, ...
das ist übrigens call by value, denn der Datentyp ist int*, und die methode bekommt eine Kopie von dem Pointer
...Das ist nicht so eindeutig. Diese "call-by-pointer-value"-Argumentation haben sich die Javaisten zurechtgelegt, um ihr Weltbild einfach zu halten, in C++ würde ich das als call-by-reference bezeichnen, weil das fachliche Objekt, mit dem man arbeiten möchte, nicht der Pointer, sondern das int ist.
Wir haben hier schon 1000 Seiten über die "call-by-"-Begriffe diskutiert und sind letztlich zu keinem Ergebnis gekommen. Letztlich sind das theoretische Konstrukte, die der Realität in der Praxis mehr oder minder eindeutig zugeordnet werden können.
template <typename T> void f(T i) { // call-by-value ? call-by-reference ? i = (T) 0xABCDEF; } struct MyClass { MyClass(int i) {} }; void g(int i) { // call-by-value ? call-by-reference ? MyClass* p = reinterpret_cast<MyClass*>(i); *p = 3; } int main() { int i=0; int* pi = &i; int& ri = i; f(i); f(pi); f(ri); g(0xABCDEF); return 0; }Gruß,
Simon2.
-
Hm je mehr Code gepostet wird, desto mehr verwirrt mich das.
Ich muss Freitag ne 4 Stunden Klausur über Theorie schreiben.
Bei Devils code müsste die Signatur ein int **arr nehmen, richtig?Und aufrufen mit &arr um die Referenz und keine Kopie zu erzeugen?