PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : C++ Referenzen


rotalever
2007-11-12, 18:16:09
Ich habe hier über die Suche bereits einen Thread über Referenzen vs. Pointern gefunden, in dem geraten wird, immer Referenzen zu benutzen, wenn es geht, weil diese immer auf ein gültiges Objekt zeigen. Soweit so gut. Angenommen ich habe eine Klasse Haus und eine Klasse Tür (blödes Beispiel...). Wird ein Objekt Haus erzeugt hat es zunächst keine Tür. Wenn man nun versuch die Funktion haus.betreten() aufruft, soll eine exception geraised werden, weil noch keine Tür vorhanden ist. Es gibt aber die Möglichkeit mittels haus.add_tür(TÜROBJEKT) eine Tür hinzuzufügen. Diese muss dann in dem Haus Objekt vermerkt werden (und das Türobjekt muss sich natürlich merken, wie oft es verwendet wird, um vermeindliches Löschen zu verhindern).

Früher hätte ich jetzt bei Haus einfach einen Pointer TÜR * tür_ptr; gespeichert, der zu Beginn den Wert NULL oder besser noch null_ptr gespeichert hat, um mir zu merken, dass noch keine Tür hinzugefügt wurde und dies zum Beispiel in der Funktion haus.betreten() testen kann. Wenn dann haus.add_tür() aufgerufen wird, wird der tür_ptr einfach entsprechend gesetzt. Wie aber macht man das mit Referenzen, da ja eine Referenz immer ein gültiges Objekt halten muss. Zu Beginn hat das Haus aber noch keine Tür, aber die Variable muss trotzdem da sein. Irgendwie ergibt das für mich ein Problem.

Desweiteren finde ich Referenzen bei Funktionsübergabe ganz nett, was mich aber stört ist, dass man dann aus dem Code nicht mehr ohne in die Funktionsdeklaration zu schauen, feststellen kann, ob diese jetzt Referenzen oder Kopien der Daten erhält. Bei Pointern hatte man beim Funktionsaufruf wenigsten noch &variable. Ich sehe auch häufig in größeren Projekten, dass Pointer verwendet werden, wo genausogut Referenzen funktionieren.

Neomi
2007-11-12, 18:31:03
Referenzen sind ja nichts anderes als implizit dereferenzierte Pointer, die immer auf ein Objekt zeigen müssen. Das kann man zwar aushebeln, indem man z.B. sagt "int &IntRef = *((int*) NULL);", aber generell kann man von gültigen Objekten ausgehen. Das Ziel einer Referenz kann nur bei ihrer Initialisierung angegeben werden, nirgendwo sonst. Als Elemente einer Struktur bzw. Klasse sind sie daher nicht zu gebrauchen (Nutzbarmachung durch Rumgefrickel, nur um sie zu nutzen, zählt nicht wirklich). Für Parameter oder als Funktionsinterne Kurzform (z.B. MyObj &obj = bla->blub.v[i].obj) sind sie gut.

Kurz: für das, was du vorhast, sind Referenzen nicht geeignet.

rotalever
2007-11-12, 19:34:59
Kurz: für das, was du vorhast, sind Referenzen nicht geeignet.
Gut, dann werde ich Pointer nehmen.

Gast
2007-11-13, 07:58:54
Ist es überhaupt sinnvoll ein Objekt, daß mal mit new erzeugt wurde als Referenz zu speichern? Da muß ich doch sowieso einmal dereferenzieren. Wie ist das eigentlich bei mehreren Referenzen eines Objekts - wenn eine den Scope verläßt ist nur die weg, das Objekt bleibt dann? Wie gebe ich die dann überhaupt wieder frei - delete funktioniert ja nur auf Pointern?

Coda
2007-11-13, 14:52:47
Ist es überhaupt sinnvoll ein Objekt, daß mal mit new erzeugt wurde als Referenz zu speichern?
Nein, auf gar keinen Fall. Das ist sogar undefiniert. Nur beim übergeben an eine Funktion dann wieder.

Wie ist das eigentlich bei mehreren Referenzen eines Objekts - wenn eine den Scope verläßt ist nur die weg, das Objekt bleibt dann?
Das Objekt bleibt natürlich.

Wie gebe ich die dann überhaupt wieder frei - delete funktioniert ja nur auf Pointern?
Über den Pointer den du von jedem allozierten Objekt irgendwo halten musst.

Gast
2007-11-21, 13:01:28
Man sieht recht häufig z.B. sowas:

static SceneManager* INSTANCE;

static SceneManager& SceneManager::getInstance()
{
// ...
return *INSTANCE
} Welchen Vorteil hat es denn eine Referenz zurückzubekommen und keinen Pointer?

Coda
2007-11-21, 13:23:05
Man spart sich die dauernde Dereferenzierung bei der weiteren Verwendung von SceneManager.

Gast
2007-11-21, 13:43:08
Ah, also Referenzen sind "ein bißchen" schneller. Und bei so Sachen wie den Singletons, die man sich vielleicht sehr oft von verschiedenen Orten holt, kann das schon etwas ausmachen? danke

Coda
2007-11-21, 14:22:29
Sie sind überhaupt nicht schneller. Es ist schlicht und einfach bloß syntaktischer Zucker.

Gast
2007-11-21, 17:22:24
Sie sind überhaupt nicht schneller. Es ist schlicht und einfach bloß syntaktischer Zucker.

Jein, je nach dem, was der Compiler daraus macht. Referenzen sind jedenfalls nur Namensaliase. Sie verbrauchen per Definition keinen Speicher. Allerdings wird ein Compiler je nach Situation evtl. dennoch Speicher dafür reservieren. Aber das ist ein Implementierungsdetail des Compilers.

Pointer hingegen verbrauchen im Gegensatz zu Referenzen aber Speicher. Es sind echte Objekte im Speicher. Nun kommt aber wieder der Compiler und optimiert evtl. den Pointer "weg".

Unterm Strich könnte beides mit einem optimierenden Compiler gleich schnell sein.

Coda
2007-11-21, 17:45:00
Jein, je nach dem, was der Compiler daraus macht. Referenzen sind jedenfalls nur Namensaliase. Sie verbrauchen per Definition keinen Speicher. Allerdings wird ein Compiler je nach Situation evtl. dennoch Speicher dafür reservieren. Aber das ist ein Implementierungsdetail des Compilers.
Referenzen bieten nicht mehr Optimierungsmöglichkeiten als Pointer. Das ist ein Gerücht.

Neomi
2007-11-21, 17:45:31
Unterm Strich könnte beides mit einem optimierenden Compiler gleich schnell sein.

Praktisch sind Referenzen nichts anderes als implizit dereferenzierte konstante Pointer (nach der Initialisierung nicht mehr zu verbiegen, nicht mit Pointern auf konstante Typen zu verwechseln). Deshalb sollte es eigentlich grundsätzlich gleich schnell sein. Optimierungspotential ist bei beiden identisch.

Gast
2007-11-22, 13:58:36
Praktisch sind Referenzen nichts anderes als implizit dereferenzierte konstante Pointer (nach der Initialisierung nicht mehr zu verbiegen, nicht mit Pointern auf konstante Typen zu verwechseln). Deshalb sollte es eigentlich grundsätzlich gleich schnell sein. Optimierungspotential ist bei beiden identisch.

Nein ist es nicht. Man kann es vielleicht so nachbilden.

int a; // 32 Bit Speicher
int b &a; // null speicher auf a; b ist nur ein weiterer Name für a
int pb *a; // weitere 32 Bit für den Pointer auf a

Wie der Compiler das löst, ist seine Aufgabe. Der Code sollte für die Referenz und den Pointer aber gleich schnell sein. Mit dem Visual C++ 6.0 Compiler habe ich aber auch schon anderes erlebt.

Neomi
2007-11-22, 14:09:40
Praktisch verhalten sich Referenzen und konstante Pointer identisch. Ein ordentlicher Compiler, der Referenzen rausoptimiert, optimiert auch den entsprechenden Pointer raus. Kann er schon den Pointer nicht rausoptimieren, würde auch die äquivalente Referenz Speicher belegen. Außerdem ist dein Beispiel syntaktisch unbrauchbar.

Gast
2007-11-22, 14:21:33
Mit dem Visual C++ 6.0 Compiler habe ich aber auch schon anderes erlebt.
Ein ordentlicher Compiler, der Referenzen rausoptimiert, optimiert auch den entsprechenden Pointer raus. Also seid ihr beide im Prinzip einer Meinung :D

Gast
2007-11-22, 15:54:34
Also seid ihr beide im Prinzip einer Meinung :D

Auf Compiler-Ebene bezogen schon.

Aber ich finde es im Moment etwas anstrengend, dass man nicht den Unterschied, zwischen Aliasing/Reference/Variable-Renaming vs. Pointer, verstehen will oder nicht verstehen kann. Eine Referenz ist KEIN statischer Pointer. Er ist ein weiterer Name für eine Adresse im Speicher und kein zusätzlicher Speicher der eine Adresse auf einen Speicherbereich enthält. Dass ein Compiler manchmal eine Referenz wie einen Pointer implementiert ist abhängig vom Code und den Optimierungseigenschaften eines Compilers.

Xmas
2007-11-22, 16:47:00
Aber ich finde es im Moment etwas anstrengend, dass man nicht den Unterschied, zwischen Aliasing/Reference/Variable-Renaming vs. Pointer, verstehen will oder nicht verstehen kann. Eine Referenz ist KEIN statischer Pointer. Er ist ein weiterer Name für eine Adresse im Speicher und kein zusätzlicher Speicher der eine Adresse auf einen Speicherbereich enthält. Dass ein Compiler manchmal eine Referenz wie einen Pointer implementiert ist abhängig vom Code und den Optimierungseigenschaften eines Compilers.
Eine Referenz als Membervariable belegt Speicher. Eine Referenz als Funktionsparameter belegt Speicher. Eine Referenz als Rückgabewert belegt Speicher. Eine Referenz die mit einem dereferenzierten Pointer initialisiert wird belegt Speicher.

Aliasing geht nur wenn bei der Zuweisung rechts ein Symbolname steht, Ausdrücke kann man nicht aliasen.
T& a = b;
T* const p = &b;
Und jeder vernünftige Compiler wird in diesem Fall auch beim const-Pointer Aliasing verwenden.

ScottManDeath
2007-11-22, 17:22:06
Aber es gibt keine Arrays von Referenzen ... was es für Pointer schon gibt ;)

Gast
2007-11-23, 16:44:23
Eine Referenz als Membervariable belegt Speicher. Eine Referenz als Funktionsparameter belegt Speicher. Eine Referenz als Rückgabewert belegt Speicher. Eine Referenz die mit einem dereferenzierten Pointer initialisiert wird belegt Speicher.

Das von mir oben Geschriebene steht in keinem Widerspruch zu deiner Aussage.
Fachlich betrachtet ist eine Referenz immer noch ein Alias.

Aber es gibt keine Arrays von Referenzen ... was es für Pointer schon gibt ;)

Der Grund steht ja weiter oben. C++ ist leider voller Kompromisse.

Bietchiebatchie
2007-11-23, 17:25:17
ich verstehe den gast schon: rein aus sprachlicher Sicht (nicht compilertechnischer) ist eine Referenz nur ein Alias; passt schon imo.

Abgesehn davon funktioniert doch folgendes nur mit Referenzen:

void foo(const int& bar) {}
und
foo(1);

void foo2(const int* bar) {}
dann funktioniert kann ich die Funktion nicht direkt mit Integern aufrufen.

Xmas
2007-11-23, 20:21:32
Das von mir oben Geschriebene steht in keinem Widerspruch zu deiner Aussage.
Fachlich betrachtet ist eine Referenz immer noch ein Alias.
Alles schön und gut, hat nur eben praktisch kaum Auswirkungen. Und das ist genau das was Neomi auch schrieb. Da brauchst du nicht mit "nicht verstehen wollen" zu kommen.

Gast
2008-01-17, 09:00:15
Ab wann "lohnt" sich eine Referenz? Macht es schon Sinn bei longs oder doubles eine Referenz als Parameter zu verwenden? Eher rein von der Theorie her, weniger ob man da wirklich was messen kann..

Coda
2008-01-17, 09:32:14
Bei "plain old data" lohnt es sich nicht, da die Argumente auch in Registern übergeben werden können.

Gast
2008-01-17, 09:47:52
Bei "plain old data" lohnt es sich nicht, da die Argumente auch in Registern übergeben werden können.Danke,
aber sobald man sowas macht, geht das nicht mehr - trotzdem nicht größer als ein double?
struct F
{
float f1, f2;
};

Coda
2008-01-17, 09:53:27
Müsste man schauen was der Compiler draus macht wenn man es ohne Referenz übergibt. Aber bist du wirklich schon an einer Stelle an der du dir über sowas Gedanken machen solltest?

Das sind eigentlich Detailoptimierungen am Ende des Projekts.

Gast
2008-01-17, 09:57:11
Aber bist du wirklich schon an einer Stelle an der du dir über sowas Gedanken machen solltest?

Das sind eigentlich Detailoptimierungen am Ende des Projekts.Nee, ich muß nicht; hatte mich nur gerade interessiert.