(lesender) Zugriff auf dafault-initialized Array Members UB?



  • Erkläre mir mal folgendes:

    foo bar = baz; // ok
    

    Wieso ist das Ok, obwohl beim unterliegenden kopieren der Member auch das uninitialisierte x einem anderen zugewiesen wird (was doch eigentlich eine lvalue-to-rvalue conversion beinhaltet), und laut unserer Diskussion UB ist?

    Ausser natürlich, du verstehst "undefined behaviour" nicht, dann frag aber bitte direkt nach.

    Ich kenne das sehr viel genauer als du, denke ich. Sag mir zum Beispiel, ob der Standard irgendwelche Anforderungen an den Programmablauf richtet, welcher vor dem UB im Programm liegt?



  • Sone schrieb:

    Erkläre mir mal folgendes:

    foo bar = baz; // ok
    

    Wieso ist das Ok, obwohl beim unterliegenden kopieren der Member auch das uninitialisierte x einem anderen zugewiesen wird (was doch eigentlich eine lvalue-to-rvalue conversion beinhaltet), und laut unserer Diskussion UB ist?

    Das musst du camper fragen nicht mich.

    [lol]

    Wo könnte da auch nur annähernd ein Problem sein?

    [/lol]

    Nicht das lvalue-to-rvalue von baz ist das Problem, sondern das lvalue-to-rvalue von baz.x (was uninitialized ist), was aber automatisch im impliziten Kopierkonstruktor vorkommt.

    Was jedenfalls eindeutig UB ist, ist

    Sone schrieb:

    Ich traue aber meinen Augen nicht, wenn ich lese,

    int a, b = a;
    

    Soll UB sein.

    Nach meinem Verständnis:

    foo a, b;
    &a; // ok
    memcpy(&a, &b, sizeof(a)); // ok
    assert(memcmp(&a, &b, sizeof(a)) == 0); // ok
    cout << a.x; // UB, a.x invalid (uninitialized)
    

    Der Standard unterscheided zwischen validen Werten und invaliden. Ein Objekt über unsigned char-Pointer zuzugreifen ist immer erlaubt, es auszulesen nur, wenn der Wert valide ist.



  • Nun, es scheint so, dass auch ein etwas anderes Verstaendnis von UB hatte. Folgt man http://en.wikipedia.org/wiki/Undefined_behavior und anderen Artikeln folgt, so muss

    int a, b;
    a = b;
    

    UB sein, weil das Resultat a der Operation = undefiniert ist, eben weil b undefiniert ist.



  • Bei Stackoverflow.com gibt es eine ähnliche Diskussion darüber: Does initialization entail lvalue-to-rvalue conversion? Is `int x = x;` UB?
    Wie soll man eigentlich korrekte C++ Programme schreiben, wenn man sich noch nicht einmal darüber einig ist, was UB ist und was nicht?



  • Was jedenfalls eindeutig UB ist

    Ach, du weißt es? Woher weißt du das?

    Nicht das lvalue-to-rvalue von baz ist das Problem, sondern das lvalue-to-rvalue von baz.x (was uninitialized ist), was aber automatisch im impliziten Kopierkonstruktor vorkommt.

    Siehe oben. Woher weißt du, dass eine lvalue-to-rvalue Umwandlung nötig ist?

    Th69 schrieb:

    Wie soll man eigentlich korrekte C++ Programme schreiben, wenn man sich noch nicht einmal darüber einig ist, was UB ist und was nicht?

    Der Fall "initialisiere eine Variable mit einer uninitialisierten anderen Variable" ist eine Ausnahme. Es gibt kaum Fälle in C++ wo es völlig unklar ist ob etwas erlaubt ist oder nicht. 🙂

    Und: was heißt hier korrekt? Dieser hier diskutierte Fall führt schon zu sowieso nicht korrektem Code - wer schreibt sowas? 😕



  • Sone schrieb:

    Siehe oben. Woher weißt du, dass eine lvalue-to-rvalue Umwandlung nötig ist?

    Das ist common sense. So common sense, dass es im Standard nur als Note festgehalten wird

    For example, the built-in assignment operators expect that the left operand is an lvalue and that the right operand is a prvalue and yield an lvalue as the result.

    Ansonsten siehe den Post von Johannes Schaub - litb im verlinkten SO für eine exakte Herleitung.



  • facepalm schrieb:

    Sone schrieb:

    Siehe oben. Woher weißt du, dass eine lvalue-to-rvalue Umwandlung nötig ist?

    Das ist common sense. So common sense, dass es im Standard nur als Note festgehalten wird

    For example, the built-in assignment operators expect that the left operand is an lvalue and that the right operand is a prvalue and yield an lvalue as the result.

    Ansonsten siehe den Post von Johannes Schaub - litb im verlinkten SO für eine exakte Herleitung.

    Dein Name passt wunderbar zu deinen Posts.
    Er* erwähnt doch noch explizit, dass assignment und initialization nicht dasselbe sind! Und das seine Schlussfolgerung nur Spekulation ist! Lern lesen!



  • Sone schrieb:

    Er erwähnt doch noch explizit, dass assignment und initialization nicht dasselbe sind! Und das seine Schlussfolgerung nur Spekulation ist! Lern lesen!

    Lern lesen! Ich schrieb Johannes Schaub - litb und nicht Andy Prowl.



  • facepalm schrieb:

    Sone schrieb:

    Er erwähnt doch noch explizit, dass assignment und initialization nicht dasselbe sind! Und das seine Schlussfolgerung nur Spekulation ist! Lern lesen!

    Lern lesen! Ich schrieb Johannes Schaub - litb und nicht Andy Prowl.

    Ja, aber du beziehst dich auf ein von Andy Prowl verlinktes Zitat - worauf denkst du habe ich geantwortet? Nur auf den ersten Teil deines Posts.



  • Sone schrieb:

    Ja, aber du beziehst dich auf ein von Andy Prowl verlinktes Zitat - worauf denkst du habe ich geantwortet? Nur auf den ersten Teil deines Posts.

    Bisschen mitdenken. Es ist common sense, dass wenn int a,b;b=a; ok ist, dann int a,b=a; das gleiche machen sollte.

    Denkst du, mein erster Teil des Posts war eine streng formale Herleitung?

    Und nein, ich denke immer noch, du hast auf meinen ganzen Post geantwortet. Passt vom Inhalt und passt auch vom Quote. Das ist nicht ersichtlich.

    Nachdem du den zweiten Teil meines Posts auch gelesen hast: Noch irgendwelche Fragen?


  • Mod

    facepalm schrieb:

    common sense

    ist immer ein logischer Trugschluss.

    Ich nehme im Übrigen die Behauptung zurück, dass

    struct foo {int x; } baz;
    foo bar = baz;
    

    kein UB hevorruft. Die verlinkte Begründung ist allerdings zwar richtig aber unvollständig (nachdem die Frage für Skalare schon geklärt wurde). Der implizit definierte Copyctor kopiert skalare Member durch direkte Initialisierung aus den Membern des Arguments - und das ist dann die Stelle, an der die l-zu-rvalue-Konvertierung benötigt wird, da Skalare nun mal mit prvalues initialisiert werden.
    Zwingend erscheint diese Regelung allerdings nicht: die Semantik hätte auch ohne Weiteres als Kopie der zugrundeliegenden Bytes erklärt werden können.


Anmelden zum Antworten