CPP-Klausur



  • hardware schrieb:

    soweit ich das verstehe, meint Arcoth solche Sachen:

    int n = (*p)++;
    

    weil nicht definiert ist, ob das ++ vor oder nach der Zuweisung geschieht. Korrigiert mich wenns falsch ist.

    ist falsch.

    int main() { 
        int m=44; 
        int *p=&m; 
    //    int &r=m; 
    //    int n=(*p)++; 
        int *q=p-1; 
    //    r=*(--p)+1;
        ++*q;
    //    ^ (zeigt eins vor 'int m' -> UB)
        cout << n << endl << &m << endl << *p << endl << r << endl << *q; 
    //                                                                ^ (zeigt eins vor 'int m' -> UB)
        return 0; 
    }
    


  • ok danke, da hab ich was falsches gemerkt, sehe jetzt auch das eigentliche UB.


  • Mod

    Das UB passiert beim p-1, denn 1 von p abzuziehen ist hier nicht erlaubt.



  • Arcoth schrieb:

    Das UB passiert beim p-1, denn 1 von p abzuziehen ist hier nicht erlaubt.

    N3337 schrieb:

    5.7 Additive operators
    2) `For subtraction, one of the following shall hold:

    — both operands have arithmetic or unscoped enumeration type; or

    — both operands are pointers to cv-qualified or cv-unqualified versions of the same completely-defined

    object type; or

    — the left operand is a pointer to a completely-defined object type and the right operand has integral or

    unscoped enumeration type.

    `

    [...]

    1. For the purposes of these operators, a pointer to a nonarray object behaves the same as a pointer to the first element of an array of length one with the type of the object as its element type.

    so weit ich das sehe, ist also T a; T* b = &a-1; kein UB sondern lediglich impl.defined behaviour (was in b bzw *b steht). UB wirds damit erst beim Zugriff auf b.

    oder lieg ich da falsch?

    bb



  • #include <iostream> 
    using namespace std;
    
    int main() {
    	int m = 44;
    	int *p = &m;
    	int &r = m;
    	int n = *(p)++;
    	int *q = p - 1;
    	r = *(--p) + 1;
    	++*q;
    	cout << n << endl << &m << endl << *p << endl << r << endl << *q;
    
    	return 0;
    }
    

    So funktioniert es einwandfrei... 🙄



  • unskilled schrieb:

    so weit ich das sehe, ist also T a; T* b = &a-1; kein UB sondern lediglich impl.defined behaviour (was in b bzw *b steht). UB wirds damit erst beim Zugriff auf b.

    oder lieg ich da falsch?

    Soweit ich weiss liegt du da falsch.
    IIRC ist sogar das UB:

    int* p = new int(42);
    delete p;
    int* p2 = p; // <-- UB
    

    Und analog dazu auch

    int* p = new int(42);
    int* p2 = p - 1; // <-- UB
    

    und auch

    int i;
    int* p = &i;
    int* p2 = p - 1; // <-- UB
    


  • mrv3112 schrieb:

    #include <iostream> 
    using namespace std;
    
    int main() {
    	int m = 44;
    	int *p = &m;
    	int &r = m;
    	int n = *(p)++;
    	int *q = p - 1;
    	r = *(--p) + 1;
    	++*q;
    	cout << n << endl << &m << endl << *p << endl << r << endl << *q;
    
    	return 0;
    }
    

    So funktioniert es einwandfrei... 🙄

    Na sowas.
    Ist ja auch ganz anderer Code.
    *(p)++ ist nicht das selbe wie (*p)++

    UB ist es allerdings vermutlich immer noch. (Oder gilt die "one past last" Ausnahme für alle Objekte und nicht nur für Arrays?)



  • hustbaer schrieb:

    IIRC ist sogar das UB:

    int* p = new int(42);
    delete p;
    int* p2 = p; // <-- UB
    

    Und analog dazu auch

    int* p = new int(42);
    int* p2 = p - 1; // <-- UB
    

    und auch

    int i;
    int* p = &i;
    int* p2 = p - 1; // <-- UB
    

    Kannst du mir nochmal erklären, was das UB jetzt genau auslöst?
    Liegt das hier daran, dass mir der der Speicher vor p ggf nicht gehört oder ist das generell nicht erlaubt?

    int i1;
    int i2;
    int* p = &i2;
    int* pvor = p - 1; // <-- auch UB ?
    

  • Mod

    int* p = new int(42);
    delete p;
    int* p2 = p;
    

    UB in C++03, implementation-defined ab C++11 (using invalid pointer value)

    int* p = new int(42);
    p - 1;
    

    UB da p und p-1 nicht auf Elemente (bzw. 1 nach dem letzten Element) des gleichen Arrays zeigen

    int i1;
    int i2;
    int* p = &i2;
    int* pvor = p - 1; // <-- auch UB ?
    

    Kein Unterschied. Die Tatsache, dass eine bestimmte Implementation sich möglicherweise dazu entscheidet, i1 unmittelbar vor i2 anzulegen (und dann ist das Ergebnis nat. definiert, weil p gleichzeitig auf eins-hinter-i1 zeigt), bedeutet nicht, dass der Standard das generell verlangt.



  • Ok, danke für die Klarstellung.



  • hustbaer schrieb:

    UB ist es allerdings vermutlich immer noch. (Oder gilt die "one past last" Ausnahme für alle Objekte und nicht nur für Arrays?)

    siehe mein post. gilt auch für (nicht-array) objekte. sollte somit well defined sein:

    #include <iostream>
    using namespace std;
    
    int main() {
    	int m = 44;
    	int *p = &m; //*p = &m
    	int &r = m; //r = m
    	int n = *(p)++; //p = &m+1; n = 44
    	int *q = p - 1; //q = &m
    	r = *(--p) + 1; //p = &m //r=m=45
    	++*q; //q=r=m=46
    	cout << n << endl << &m << endl << *p << endl << r << endl << *q; //ok
    //44
    //[&m] (adresse von m)
    //46
    //46
    //46
    	return 0;
    }
    

Anmelden zum Antworten