Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

Evrey

Treue Seele

Beiträge: 245

Beruf: Weltherrscher

  • Private Nachricht senden

21

10.09.2014, 14:30

Dann hast du den Unterschied nicht begriffen, aber ich führe für dich nochmal die zwei Kern-Unterschiede auf:
  • Pointer müssen nicht immer auf ein gültiges Objekt verweisen (nullptr), Referenzen verweisen hingegen immer auf ein gültiges Objekt.
  • Pointer kennen Arithmetik. Du kannst also aus Pointern zu einem Objekt einen Pointer zu einem anderen Objekt berechnen, was eine potenziell gefährliche Operation ist. Referenzen können das nicht.
Zum ersten Punkt sei zusätzlich angemerkt, dass es Sprachen gibt, die spezielle Referenz-Typen haben, die ebenfalls nicht immer auf gültige Objekte verweisen müssen. Siehe C# und Java.

C-/C++-Quelltext

1
2
3
4
int main(int _argc, char** _argv) noexcept {
  asm volatile("lock cmpxchg8b %eax");
  return 0;
} // ::main
(Dieses kleine Biest vermochte einst x86-Prozessoren lahm zu legen.)

=> Und er blogt unter Hackish.Codes D:

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

22

10.09.2014, 14:43

Referenzen verweisen hingegen immer auf ein gültiges Objekt.

Das stimmt so aber auch nicht.
Was hält mich davon ab, eine Referenz auf ein mit new erzeugtes Objekt zu erzeugen, welches ich dann lösche?

Architekt

Community-Fossil

Beiträge: 2 481

Wohnort: Hamburg

Beruf: Student

  • Private Nachricht senden

23

10.09.2014, 14:47

Referenzen verweisen hingegen immer auf ein gültiges Objekt.

Das stimmt so aber auch nicht.
Was hält mich davon ab, eine Referenz auf ein mit new erzeugtes Objekt zu erzeugen, welches ich dann lösche?

Ach, geht doch noch viel simpler:

C-/C++-Quelltext

1
2
    int* p = nullptr;
    int& pr = *p;

:thumbup:
Der einfachste Weg eine Kopie zu entfernen ist sie zu löschen.
- Stephan Schmidt -

Evrey

Treue Seele

Beiträge: 245

Beruf: Weltherrscher

  • Private Nachricht senden

24

10.09.2014, 14:51

Das ist eher ein Exploit der zu undefined Behavior führt. Das "immer" bezog sich darauf, dass es eine solche Semantik nicht gibt:
T& _ref = null;
Wenn ich mich recht entsinne, ging das in C# mit "?", also...
T? _ref = null;
Aber keine Garantie für syntaktische Korrektheit. Ewig nicht mit C# hantiert.

C-/C++-Quelltext

1
2
3
4
int main(int _argc, char** _argv) noexcept {
  asm volatile("lock cmpxchg8b %eax");
  return 0;
} // ::main
(Dieses kleine Biest vermochte einst x86-Prozessoren lahm zu legen.)

=> Und er blogt unter Hackish.Codes D:

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

25

10.09.2014, 14:53

Normale Referenzen in C# können null sein.
T? ist nur ein Shortcut für Nullable<T>, welches es erlaubt, auch Werttypen (z.B. int) auf "null" zu setzen.

Beiträge: 1 223

Wohnort: Deutschland Bayern

Beruf: Schüler

  • Private Nachricht senden

26

10.09.2014, 15:22

Außerdem...
  • Referenzen sind unveränderbar, Zeiger können jederzeit einem neuen Wert zugewiesen werden.
  • Zeiger sind erforderlich um Speicher dynamisch zu verwalten.

Theoretisch könnten Zeiger Referenzen rein von der Funktionalität eher ersetzen(Siehe C) als andersrum.
Referenzen sind so in etwa "konstante Zeiger mit integrierter Dereferenzierung" und sind für den saubereren Syntax notwendig.
Ganz besondere spezielle Rolle spielen sie aber auch nochmal bei der Move-Semantik.

Null-Referenzen dürfte es in einem C++ Programm wohl nicht geben, weil wie Evrey schon sagte, sie scheinbar undefined Behavior sind. Praktisch kann es sie theoretisch natürlich geben, sollte es jedoch trotzdem nicht.

27

10.09.2014, 18:19

Mindestens genau so wichtig, wenn nicht sogar wichtiger ist allerdings die Frage, wieso man überhaupt gerade etwas am Heap allokieren will...

Also mir ist ja klar, dass man Variablen am Stack schneller anlegen kann als am Heap. Aber was ich mich frage ist, wie man weitestgehend auf den Heap verzichten können soll.
Sagen wir ich habe eine dynamische Anzahl an Spielobjekten. Dann führt im Grunde kein weg daran vorbei, dass sie am Heap landen. Außerdem würde ich sie im Normalfall in einen std-Container packen, und da werden Objekte nunmal hin und her kopiert. Also nehme ich einen Container mit std::uniqu_ptr, weil ich keine Lust habe, komplexe Objekte zu kopieren. Aber selbst wenn ich keine Zeiger im Container hätte, da er dynamisch alloziert ist, wären die Objekte doch so oder so am Heap. Was wäre also dein Vorschlag?

Zu shared_ptr: Benutze ich eigentlich nie. Wenn ein Objekt von mehreren anderen Objekten benutzt wird, kann man meistens eines davon als den Besitzer ausfindig machen, dieser hat dann einen unique_ptr, während die anderen dann nur einen normalen raw-pointer benutzen. Oder halt eine Referenz. Es muss nur sichergestellt sein, dass der Besitzer länger lebt als alle Benutzer, aber das ist in der Regel sehr einfach.
Das schöne an unique_ptr ist dann auch, dass du explizit modellierst, wer Besitzer und wer Benutzer ist. Und wenn du Zeiger an Funktionen übergibst, siehst du schon an der Deklaration, ob das Objekt den Besitzer wechselt oder nicht. Wenn du das konsequent machst, kannst du garantieren, dass jedes dynamisch erzeugte Objekt immer genau einen Besitzer hat und auch garantiert freigegeben wird, sobald es nicht mehr benötigt wird. Das ist um ein vielfaches effizienter als jeder Garbage-Collector. Und es macht den Code schöner und aussagekräftiger. Meiner Meinung nach hat C++ damit die schönste und sauberste Speicherverwaltung aller Programmiersprachen die ich kenne.
Lieber dumm fragen, als dumm bleiben!

28

10.09.2014, 20:50

Außerdem würde ich sie im Normalfall in einen std-Container packen, und da werden Objekte nunmal hin und her kopiert. Also nehme ich einen Container mit std::uniqu_ptr, weil ich keine Lust habe, komplexe Objekte zu kopieren.

Kopieren ist so nicht richtig. Wenn du garantierst, dass dein move-Konstruktor keine Exceptions wirft (noexcept), wird dieser auch benutzt.
"Theory is when you know something, but it doesn’t work. Practice is when something works, but you don’t know why. Programmers combine theory and practice: Nothing works and they don’t know why." - Anon

Werbeanzeige