Random-Access-Iteratoren über das ende des Bereiches hinaus Vergleichen



  • Nathan schrieb:

    Warum willst du das auch machen?

    Dürfte offensichtlich sein: Einfacherer Code.



  • Nein, ich mein:
    Was will er mit einem Iterator, der hinter end() zeigt?
    Ich mein, selbst testen, ob der gültig ist, ist undefiniert, oder?



  • Nexus schrieb:

    Nathan schrieb:

    Warum willst du das auch machen?

    Dürfte offensichtlich sein: Einfacherer Code.

    Es sind die obskursten Dinge in C++ erlaubt. Wieso sollte da etwas so simples wie

    If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined.

    nicht erlaubt sein...?* Aber offensichtlich ist das so. Merkwürdig. Danke Bashar, das wusste ich nicht - recht unintuitiv.

    ändere doch einfach die Abbruchbedingung.

    👍
    Es wird aber auch so zu kompliziert.

    *: Die Aussage lässt sich auch anders interpretieren, aber das wäre weit hergeholt.



  • Nathan schrieb:

    Was will er mit einem Iterator, der hinter end() zeigt?

    Er will ja keinen Iterator, der hinter end() zeigt, sondern über jedes dritte Element iterieren. Und mit dem naheliegendsten Code (wie man ihn von Ganzzahlen-Iterationen kennt) kommt eben UB zustande.

    Sone schrieb:

    Wieso sollte da etwas so simples wie [...] nicht erlaubt sein?

    Weil man dadurch die Implementierung zwingen würde, realitätsferne Fälle richtig zu behandeln, möglicherweise auf Kosten der normalen Benutzung.



  • Weil man dadurch die Implementierung zwingen würde, realitätsferne Fälle richtig zu behandeln, möglicherweise auf Kosten der normalen Benutzung.

    Was muss die Implementierung denn machen, wenn ich einfach einen Zeiger mit einem Skalar addiere? Sie muss einfach brav die Addition durchführen und beim Vergleich in der Abbruchbedingung false zurückliefern (bzw. true wenn ein Overflow aufgetreten ist).
    Es ist nichts weiteres als Skalararithmetik mit Zeigern. Darf ich denn den Zeiger zu einem Skalar casten (per reinterpret_cast ) und diesen dann mit einem anderen Skalar addieren sodass ich eine Abbruchbedingung erstellen kann die kein UB ist? Natürlich. Mit Zeigern darf man nicht, weil ...?



  • Okay, dann eben keine Pointer sondern ein Index.

    5.7p5 sagt undefined.

    Ich tippe mal auf den von Sone zitierten Test:

    If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined.

    D.h. wenn meine Zeigeroperation keinen Ueberlauf produziert, dann ist alles im gruenen Bereich?



  • Sone schrieb:

    Es ist nichts weiteres als Skalararithmetik mit Zeigern. Darf ich denn den Zeiger zu einem Skalar casten (per reinterpret_cast ) und diesen dann mit einem anderen Skalar addieren sodass ich eine Abbruchbedingung erstellen kann die kein UB ist? Natürlich.

    Natürlich nicht.

    Mit dem intptr_t (hab vergessen wie der genau heisst) kannst du keine Pointerarithmetik betreiben.



  • D.h. wenn meine Zeigeroperation keinen Ueberlauf produziert, dann ist alles im gruenen Bereich?

    Eben das meinte ich mit 'anders interpretieren'. Das wäre aber wie gesagt weit hergeholt.
    Oder nicht? Ich bin verunsichert.



  • pragma ticker schrieb:

    Mit dem intptr_t (hab vergessen wie der genau heisst) kannst du keine Pointerarithmetik betreiben.

    Wieso nicht? Dürfen wir auf einmal nicht einmal mehr mit gewöhnlichen int s so hantieren wie wir wollen?

    auto scalar = reinterpret_cast<std::uintptr_t>(array_anfang);
    scalar += beliebig; // Kein UB, ich darf Späße treiben wie ich lustig bin
    // ...
    


  • Sone schrieb:

    D.h. wenn meine Zeigeroperation keinen Ueberlauf produziert, dann ist alles im gruenen Bereich?

    Eben das meinte ich mit 'anders interpretieren'. Das wäre aber wie gesagt weit hergeholt.

    Der Memory in C++ ist nicht zwingend ein grosses Array.



  • Sone schrieb:

    Dürfen wir auf einmal nicht einmal mehr mit gewöhnlichen int s so hantieren wie wir wollen?

    Du darfst damit rechnen, was du willst. Es muss nur überhaupt keine Entsprechung mit richtigen POintern haben und zurückcasten darfst du auch nicht.

    An integer value is an integer representation of a safely-derived pointer only if its type is at least as large as
    std::intptr_t and it is one of the following:
    — the result of a reinterpret_cast of a safely-derived pointer value;
    — the result of a valid conversion of an integer representation of a safely-derived pointer value;
    — the value of an object whose value was copied from a traceable pointer object, where at the time of
    the copy the source object contained an integer representation of a safely-derived pointer value;
    — the result of an additive or bitwise operation, one of whose operands is an integer representation of a
    safely-derived pointer value P, if that result converted by reinterpret_cast<void*> would compare
    equal to a safely-derived pointer computable from reinterpret_cast<void*>(P).



  • knivil schrieb:

    If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined.

    D.h. wenn meine Zeigeroperation keinen Ueberlauf produziert, dann ist alles im gruenen Bereich?

    Nein.

    If
    both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object,
    [then]
    the evaluation shall not produce an overflow;
    otherwise,
    the behavior is undefined.



  • pragma ticker schrieb:

    Es muss nur überhaupt keine Entsprechung mit richtigen POintern haben

    Doch. Caste ich int* zu int , hat int (vorausgesetzt es ist groß genug) denselben Wert.
    Und wenn ich sizeof(A)*k dazu addiere, ist es derselbe Wert wie als wenn ich nur k dazuaddieren würde, auf den originalen Zeiger. Nur dass das dann UB wäre.

    und zurückcasten darfst du auch nicht.

    Das ist klar, hatte ich nie vor.

    pragma ticker schrieb:

    Der Memory in C++ ist nicht zwingend ein grosses Array.

    Was meinst du jetzt? Es ist definiert, dass immer ein Byte hinter jedem Array existiert.



  • Sone schrieb:

    Doch. Caste ich int* zu int , hat int (vorausgesetzt es ist groß genug) denselben Wert.

    Wer sagt das? Bzw. wie willst du die Werte überhaupt vergleichen? Soweit ich weiss, ist die interne Repräsentation von Zeigern nicht vorgeschrieben.

    Sone schrieb:

    Was meinst du jetzt?

    Es gibt andere Speichermodelle als das typische RAM mit fortlaufend adressierten Zellen.



  • Sone schrieb:

    pragma ticker schrieb:

    Es muss nur überhaupt keine Entsprechung mit richtigen POintern haben

    Doch. Caste ich int* zu int , hat int (vorausgesetzt es ist groß genug) denselben Wert.
    Und wenn ich sizeof(A)*k dazu addiere, ist es derselbe Wert wie als wenn ich nur k dazuaddieren würde, auf den originalen Zeiger. Nur dass das dann UB wäre.

    Beachte:

    The mapping function is
    implementation-defined.

    Vielleicht macht reinterpret_cast<int>(p) das gleiche wie -13*p + 17 . Erlaubt wäre es zumindest. Und dann sagt dein Rumgerechne absolut nichts aus.


Anmelden zum Antworten