void reference?
-
@Shade
template <class T> T& invalid_ref(T* x) { T* tmp = NULL; return *tmp; //hier oops // nope } int main() { int a = 1; int& b = invalid_ref(&a); b = 2; // oops :-o //nein, hier kein oops // definitiv hier oops }operator void schrieb:
Bestimmt nicht gerade sinnvoll, aber "," überladen zu können war auch nicht gerade sinnvoll
Ich geb ja zu, dass C++ einige Syntax Kinderkrankheiten hat (ich sag nur logical xor), aber mit void* kann man all das machen, was der eine oder andere mit void& machen möchte. Und man sollte sein Codedesign nochmal überdenken, wenn man void Objekte nach "aussen" geben muss.
-
template <class T> T& invalid_ref(T* x) { T* tmp = NULL; return *tmp; //hier oops // nope // dereferenzieren von NULL, also oops } int main() { int a = 1; int& b = invalid_ref(&a); b = 2; // oops :-o //nein, hier kein oops // definitiv hier oops // quark }
-
Helium schrieb:
template <class T> T& invalid_ref(T* x) { T* tmp = NULL; return *tmp; //hier oops // nope // dereferenzieren von NULL, also oops } int main() { int a = 1; int& b = invalid_ref(&a); b = 2; // oops :-o //nein, hier kein oops // definitiv hier oops // quark }Warum sollte das gehen? b is doch ne Nullreferenz. Das kann doch nicht gehen...
-
Du hast vorher Null dereferenziert!
-
Mit dem oops ist es so eine Sache: dieses oops sagt aus: 'Undefiniertes Verhalten'
Das bedeutet aber nicht, dass es auch schon hier abstürtzen muss. Es kann genausogut erst später oder auch garnicht Abstürzen.
Das ist das gemeine an Undefiniertem Verhalten...
-
@Shade
Hier gibt es kein Undefiniertes Verhalten. Das Programm stürzt immer ab, es sei denn man kann den Zugriff auf NULL-Speicher abfangen (kann ich im Moment net sagen ob und wie's geht).Ich weiss nicht, ob einige Leute den Code mal durch nen Debugger gejagt haben. Mir kommts so vor als ob das einige mal tun sollten. Vielleicht ist da ja auch jeder Compiler anders gepolt. Beim MSC jedenfalls ergibt sich das Verhalten so wie ich es erklärt habe und das ist für mich logisch.
template <class T> T& invalid_ref(T* x) { T* tmp = NULL; return *tmp; // hier wird nicht NULL dereferenziert, sondern tmp // und tmp ist eine gültige Variable mit gültigem Speicher // dass tmp ein Zeiger ist, der auf NULL zeigt -> geschenkt // letztendlich wird zwar ein NULL Objekt zurückgegeben, // interessiert hier aber nicht, da ich weder lesend noch // schreibend zugreife } int main() { int a = 1; int& b = invalid_ref(&a); b = 2; // erst hier machts oops, weil ich jetzt auf ein NULL-Objekt // schreibend zugreife }
-
groovemaster2002 schrieb:
@Shade
Hier gibt es kein Undefiniertes Verhalten. Das Programm stürzt immer ab, es sei denn man kann den Zugriff auf NULL-Speicher abfangen (kann ich im Moment net sagen ob und wie's geht).... oder man hat ein System ohne Speicherschutz (MS-DOS, alte MacOS-Versionen etc.). Ich weiß nicht, was du unter undefiniertem Verhalten verstehst. Wir verwenden hier jedenfalls die Bedeutung aus dem C++-Standard, und nach der bedeutet das schlicht und einfach, dass der Standard keinerlei Forderungen an den Effekt stellt. Ein Absturz ist genauso zulässig wie irgendwas anderes, egal was.
-
groovemaster2002 schrieb:
template <class T> T& invalid_ref(T* x) { T* tmp = NULL; return *tmp; // hier wird nicht NULL dereferenziert, sondern tmp // und tmp ist eine gültige Variable mit gültigem Speicher // dass tmp ein Zeiger ist, der auf NULL zeigt -> geschenkt // letztendlich wird zwar ein NULL Objekt zurückgegeben, // interessiert hier aber nicht, da ich weder lesend noch // schreibend zugreife } int main() { int a = 1; int& b = invalid_ref(&a); b = 2; // erst hier machts oops, weil ich jetzt auf ein NULL-Objekt // schreibend zugreife }vielleicht solltest du nicht den debugger bemühen, sondern ein gutes Buch?
Der Grund warum er dort oben nicht abschmiert ist wahrscheinlich der, dass Referenzen intern als Zeiger gehandhabt werden und keine Dereferenzierung stattfindet.
Das ist aber Implementierungsabhängig...
-
per definitionem erzeugt das dereferenzieren eines zeigers, der auf NULL zeigt, undefiniertes verhalten - so der standard.
und undefiniertes verhalten heißt, wie der name schon sagt, es kann geschehen, was geschehen will.
-
Der Compiler könnte die Dereferenzierung allerdings wegoptimieren, wenn er sieht, dass der Zeiger dereferenziert und dann direkt an die Referenz übergeben wird, das könnte ich mir auch vorstellen.
-
Der Standard erwähnt sogar ausdrücklich, dass in einem legalen Programm Referenzen auf Null nicht vorkommen können - weil man sie eben nur erzeugen kann, wenn man einen Nullzeiger dereferenziert (8.3.2)
Egal ob der Compiler etwas wegoptimieren kann oder nicht - Wenn es so im Code steht, dann ist es einfach undefiniert, was herauskommt.
-
Ich habe beim MSVC sogar schon ne Referenz angelegt, die ich nicht
initialisiert habe und erst spaeter auf eine Variable habe referenzieren
lassen
Sollte er das eigentlich nicht _nicht_ schlucken?

Soviel zum manchmal komischen Verhalten vom MSVC

mfg
v R
-
Da würde mich ja interessieren, wie du das gemacht hast.
-
Bashar schrieb:
Da würde mich ja interessieren, wie du das gemacht hast.
Na das weisst du doch, war doch damals mit dir im chat und hatte den Code auch
irgendwo auf rafb gepostet gehabt...mal sehn ob ich den wiederfinde. Weiss noch,
dass der Borland-Compiler und der gcc den Code nicht geschluckt hat.War glaub ich sowas in der Art:
int &i; int j; i = j;Ich schau nochmal nach, ansonsten kann ich ja nochmal MSVC installieren und
das ganze nochmal machen.Wenn jemand das Visual Studio.net 2002 hat, sollte er das Ganze nachvollziehen
koennen.mfg
v R
-
davie schrieb:
Der Standard erwähnt sogar ausdrücklich, dass in einem legalen Programm Referenzen auf Null nicht vorkommen können - weil man sie eben nur erzeugen kann, wenn man einen Nullzeiger dereferenziert (8.3.2)
Der Standard spricht nicht von legalen, sondern von "well-defined
program". Und genau mit dieser Aussage bestätigst du, dass sich der Code so verhält, wie ers tut.T* tmp = NULL; return *tmp;Hier passiert nix undefiniertes. Es wird laut Standard eine null reference "erzeugt". Was damit passiert ist undefiniert (geb ja zu, dass dies nicht immer zu einem Absturz führen muss - auch wenn das auf x86 Plattformen die Regel sein wird). Mich störte nur, dass Shade schrieb:
b = 2; // oops :-o //nein, hier kein oopsWenn das Programm nicht irgendwo nach dem return sich undefiniert verhält, hier tut es das auf jeden Fall. Mir geht es aber nicht darum zu streiten, wo's oopst, sondern dass man die "sicheren" Referenzen auch missbrauchen kann.
-
groovemaster2002 schrieb:
Hier passiert nix undefiniertes.
Soll ich dir den Standard vorlesen?
hier mal ganz langsam zum mitschreiben:
in particular, a null reference cannot exist in a well-defined program, because the only way to create such a reference would be to bind it to the "object" obtained by dereferencing a null pointer, which causes undefined behavior.
Was ist daran unverständlich?
Wenn dir "well-defined" nicht gefällt, siehe 1.3.* - dort gibts n paar Erklärungen die du dir mal reinziehen solltest.
-
Sicherlich kann man den Satz unterschiedlich interpretieren, ich lese da 2 Fakten raus:
1. das Dereferenzieren eines Null-Zeigers ergibt immer eine Null-Referenz - da is nix undefiniert dran
2. die Auswirkungen durch die Benutzung einer Null-Referenz sind dagegen undefined, weshalb man sie in einem "well-defined" Programm nicht benutzen soll.
-
du interpretierst ihn aber falsch.
-
mit der zeile
return *tmp;dereferenzierst du einen nullzeiger, zumindest darüber sind wir uns einig?
-
A macht was kaputt, so daß B nicht mehr funktioniert. Wo gehört jetzt das Oops hin? Da wo A was kaputt macht (meine Meinung) oder da wo jemand ahnungsloses versucht B trotzdem zu benutzen?