Suche richtige Bezeichung für bestimmte Methodenaufrufe wie z.B Call by reference

Dizzy_Ti

Vice Admiral Special
Mitglied seit
11.11.2001
Beiträge
667
Renomée
0
Standort
Düsseldorf
Hi,
wie nennt man folgende Aufrufe im Fachvokabular:
Code:
double sqrt(long *value)
{

}
double sqrt(long &value)
{
}
double sqrt(long value)
{
}
long zahl;
long *value=new long();
sqrt(&value);// Wie nennt man diesen Aufruf
sqrt(*value);// ""
sqrt(zahl);// " "
 
Tach erstmal

Code:
double sqrt(long *value)
{
}
call by pointer?

Code:
double sqrt(long &value)
{
}
call by reference.

Code:
double sqrt(long value)
{
}
call by value.

Code:
long zahl;
long *value=new long();
sqrt(&value); // Call by reference
sqrt(*value); // Call by pointer?
sqrt(zahl);   // Call by value

Beim call by pointer bin ich mir nicht sicher ob man das so nennt ...
 
Call by Reference sollte man tunlichst sein lassen, weil es aus dem Code nicht so ohne weiteres hervorgeht, und wenn man mal etwas unsauber proggt debuggt man sich zu tode *chatt*

Aber besondere Namen - außer ByRef und ByVal (ok, so heist es in Basic, wo ich das das letzte mal gebraucht hab - also By Reference und By Value) kenn ich dafür auch net. ByRef ist wie gesagt ziemlich unsauber, und man sollte dafür besser Pointer nehmen (Pointer werden übrigens ByValue übergeben).

C macht dir bei ByRef übrigens einen automatischen Typecast (bei pointern afair auch), und so wie du das geschrieben hast haut es auch nicht ganz hin.

Code:
long zahl;
long *value=new long();
sqrt(&value); // Ist nicht sinnvoll, das ist ein Zeiger auf einen Zeiger - also sqrt(** int)
sqrt(*value); // Das ist ByValue
sqrt(zahl);   // Und das ist auch ByValue
 
Original geschrieben von intel_hasser
Call by Reference sollte man tunlichst sein lassen, weil es aus dem Code nicht so ohne weiteres hervorgeht, und wenn man mal etwas unsauber proggt debuggt man sich zu tode *chatt
Einspruch!
Sobald du größere Objekte hast, sollte man tunlichst Call-By-Reference benutzen! Ansonsten hast du das Problem, dass sich dein Rechner zu Tode kopiert, nur weil du bei jedem Methodenaufruf Call-By-Value nimmst...

Übrigens, gibt es nicht auch so etwas wie Call-By-Copy-And-Restore??
 
Nein, wenn du einen Zeiger übergibst ist das auch ByValue ;)
Das bevorzuge ich auch.

ByReference hat das Problem, dass es aus dem Code nicht ersichtlich wird. Also wenn du den Funktionsaufruf a(x); hast, siehst du nicht ob x ByValue oder ByReference ist. Desswegen immer ByValue.
Wenn du das als Zeiger übergibst wird das sehr deutlich, dann ist es "a(&x)";.
 
Wenn du was per Value übergibst wird der Wert kopiert.

By Reference bleibt die Variable an ihrem ursprünglichen Speicherort die Funktion greift per Pointer auf die Adresse zu.

Ich seh nicht wo das Problem mit der übergabe by Reference ist, wenn du die Übergebene Variable in der Funktion selbst nicht veränderst.

In Java werden alle Objekte per Reference übergeben. Primitive Datentypen werden dagegen immer per Value übergeben. Um in Java Primitive Datentypen per Reference zu übergeben muss man sich eines Tricks behelfen. Am einfachsten die zu übergebene Variable in einem Array speichern.
 
Original geschrieben von intel_hasser
Nein, wenn du einen Zeiger übergibst ist das auch ByValue ;)
Das bevorzuge ich auch.
Ach so meinst du das. ;) Na dann ist Okay. Ich dachte schon du willst ganze Objekte by Call übergeben... 8)
 
Hi.
Die Argumentation von intel_hasser ist durchaus nachvollziehbar, aber den Ausdruck "unsauber" in diesem kontext zu verwenden dürfte für viele C++ Programmierer ein Schlag ins Gesicht sein. Referenzen sind nichts anderes als Zeiger, nur muss man nicht ständig Operatoren platzieren.
Deine Aufgabe als Coder ist es einerseits deine Funktionen so zu nennen und zu kommentieren dass ersichtlich wird was für Werte wie übernommen werden, und ebenso zu lesen welche Funktion die du einetzt einen Wert wie übernimmt und verarbeitet. Wenn du das nicht machst arbeitest du unsauber, aber das auf die Referenzen zu schieben wäre ungerecht.

Beispielsweise ist es nur durch Referenzen oder Zeiger möglich die Objekte fremder Klassen in einer eigenen Klasse zu verwursten. Wenn du nun aber jedesmal dieses (nervige) "&" vor deine Variablen setzen musst, und bei jeder Operation dann wieder dereferenzieren... das sieht dann wirklich unsauber aus, und ist nachtträglich sehr schwer auseinander zu klauben. Zugegeben, ich verwende Referenzen auch fast nie, sondern lieber Zeiger, aber deswegen würde ich Referenzen nicht als "unsauber" abstempeln.

Wie war das nochmal bei Java? Es werden glaub ich solange Referenzen benutzt, bis ein Objekt geändert wird. Erst dann wird eine Kopie angelegt. Ausser man hat eindeutig kundgetan dass man das Original bearbeiten will. Stimmt das?

so long,
exr
 
Nein, es gibt noch ein anderes ByReference, wie gesagt, Zeiger werden auch ByValue übergeben.

Unterschied:

Code:
int* ptr_a;
int b;

void fa(int &a) {a=3;}
void fb(int* a) {a=NULL;}
void fc(int b)  {b=4;}
void fd(int* &b)  {b=NULL;}


int main()
{
  fa(b);     // echtes by Reference - nach dem Aufruf ist b=3
  fb(a);     // ByValue, a ist nach dem Aufruf nicht NULL
  fc(b);     // ByValue, b ist nach dem Aufruf nicht 4
  fd(a);     // ByReference, a ist nach dem Aufruf NULL  
}

Es ist wie man sieht schon ein Unterschied, ob man einen Pointer oder einen Wert by Reference übergibt (wobei man auch Pointer By Reference übergeben kann).

Wenn man einen Wert über einen Pointer als Referenz übergibt wird das sehr gut sichtbar, nämlich zb. am "fb(&b);" - bei fa wird aber nicht ersichtlich, dass sich b ändert.

Große Klassen sollte man aber sowieso nicht lokal deklarieren, sondern nur einen lokalen Zeiger auf die Klasse. Das ist eher wegen Kompatiblität, weil andere Programmiersprachen Klassen immer als Zeiger darauf deklarieren, zb. Delphi - aber abgesehen davon ist es auch sauberer weil, weniger Stack verpulvert wird (<- wichtig), die Klasse nach dem Beenden der Funktion weiterexistiert (bzw. gibts da keinerlei Probleme mit) und der Stack ist manchmal auch ein heißes Pflaster ;).

Also lieber sowas:

Code:
class Ca {...};

int main()
{
  Ca *a;       // richtig
  a=new Ca();  

  Ca b(); // falsch

  delete a;
  return 0;
}
 
Also auf die Idee einen Zeiger als Referenz zu übergeben bin ich noch nicht gekommen. Ich glaube da wirds wirklich unsicher. Wenn du einen Wert einer Variable überschreibst, schmiert das Programm vielleicht ab oder errechnet erstaunliche Ergebnisse.
Wenn du aber einen Zeiger änderst geht dir möglicherweise der Speicher verloren, du schreibst in Speicher der dir nicht gehört (was immer gefährlich sein kann) usw.

Also wenn du schon argumentierst dass ein Aufruf durch Referenz-Parameter verwirrend sein kann (da schlecht zu debuggen - obwohl man das im Code ja sieht beim debuggen), müsstest du bei einem Zeiger als Referenz eigentlich auf die Barrikden gehen. Das ist ja noch ein vielfaches schlimmer! ;D ;)

exr
 
Na da kannst du doch 2 Elterklassen bilden (ByRef und ByVal), die von den Fällen oben implementiert werden *buck*

Natürlich ist "int* &a" die Krönung des Schwachsinns ;)

Viel sauberer wäre da "int* fkt(int* a);" - da wird sofort ersichtlich, dass sich da etwas verändert, und die Codezeile "x=fkt(x);" sagt dann auch alles.

Man sollte es auch tunlichst vermeiden einen ByRef Zeiger (der ansich ja nicht schlimmer ist als andere ByRef Sachen) in einer Funktion einfach mal auf NULL zu setzen. Da ist ärger vorprogrammiert.
Prinzipiell - wenn richtig angewandt - ist das aber kein Problem. Ein denkbares Beispiel wäre sowas:

Code:
void increase(int* &x)
{
  x=realloc(x, 1234567890);
  return;
}

Würde funktionieren (um zb. die Größe eines Arrays zu ändern), ist aber eben ziemlich unsauber wegen dem ByRef. Das mit "int* increase(int* x);" zu lösen ist aber auch nicht perfekt, x ist nämlich nach dem Funktionsaufruf ungültig - das wird nicht ersichtlich.
Bei einem Aufruf der Form "y=increase(x);" wird das dann nicht deutlich und wenn man später auf x zugreift wirds spannend ;D.
Da müsste man dann x nach dem Funktionsaufruf explizit auf NULL setzen, das ergibt nämlich in 99.9% aller Fälle wenigstens eine Fehlermeldung und keinen Datenschrott.

Aber im Grunde genommen kann man sowas schon brauchen. Zb. könnte man eine Grundklasse in dieser Funktion 1mal ableiten und ein paar Werte der Ausgangsklasse reinkopieren - dadurch ändert sich dann auch der Zeiger, der dann aber trotzdem per Rückgabewert zurückgegeben werden sollte.

Die übergebene Klasse (die wir dabei per Zeiger übergeben, wie gesagt, es ist praktisch unsauber Klassen nicht per Zeiger zu behandeln) können wir dann in der Funktion löschen und damit haben wir nichtmal ein Speicherleck.

Also wenn du schon argumentierst dass ein Aufruf durch Referenz-Parameter verwirrend sein kann (da schlecht zu debuggen - obwohl man das im Code ja sieht beim debuggen)
Das ist es ja eben, man sieht es nicht beim Debuggen. Wenn ein Zeiger erwartet wird sieht man das an dem &, wenn die Funktion aber eine Referenz erwartet sieht man es nicht. Also "void a(int &b);" und "void b(int b);" haben ganz genau den selben Aufrufsyntax, sowohl "a(int x);" als auch "b(int x);" sind gültige Funktionsaufrufe.
Intern wird ByReference auch anders behandelt als ein übergebener Zeiger. Die Werte selbst weden dann schon direkt auf den Stack gelegt (also im Fall von "b(x);" wird x auch wirklich auf den Stack gelegt, und nicht nur ein Zeiger auf x), allerdings legt b am Ende x wieder auf den Stack zurück und der Aufrufcode liest x vom Stack in die Parametervariable x. Das macht ByReference auch ziemlich langsam.

PS Wer die 80/20 Regel aufgestellt hat, hat maßlos untertrieben - müsste eigentlich 95/5 lauten ;D
 
Zurück
Oben Unten