Der this-Zeiger im if



  • Nexus schrieb:

    Ja, im alten Standard war die Nullzeiger-Dereferenzierung undefiniertes Verhalten. Eine Ausnahme war die Existenzgrundlage von std::bad_typeid . Ich weiss nicht, in wie fern sich C++11 hier geändert hat [...]

    Nexus schrieb:

    Das Makro NULL ist in C++ gerade als 0 definiert, nullptr ist die typsichere C++11-Variante.

    In C++11 hat sich beides geändert. Nullzeiger-Dereferenzierung ist erlaubt, solange es eine prvalue bleibt (und nicht in decltype oder so auftritt).

    Und NULL darf auch nach nullptr definiert sein.

    Davon abgesehen tritt in meinem Code nicht einmal "delete p" auf (ausser vielleicht in Custom Deletern für Smart-Pointer).



  • int main(){
    	Test *t = reinterpret_cast<Test *>(sizeof t);
    	t[-1].f();
    }
    

    UB?
    Wenn t = 0 nichts mit der Speicheradresse 0 zu tun hat dann müsste ja folgendes gelten:

    Test *t = 0;
    t++; //kann man den 0-Pointer überhaupt incrementieren?
    assert(t == 0);
    


  • Hi

    Ok ein bisschen viel Text und allem kann ich nicht folgen :).
    Ich beziehe mich auf das ähneliche Bspiel von dd++

    Zuerstmal if(!this) ein bisschen "augenfreundlicher" geschrieben steht für if(this==0) :).
    Das heißt doch, das tritt nur dann auf wenn es für adr keine Instanz gibt richtig ?

    Also wenn ich sowas mache:

    struct adr
    {
       string name;
       string adresse;
       adr *next;  
       ///....
       void del()
       {
          if(!this) return;
          if(next)
          {
            ....
          }
       }
    }
    
    int main()
    {
       adr adress*;
       adress->del();
    
       retrun 0;
    }
    

    man "will"/wollter sich vor einer Exception schützen wenn jemand sowas, wie oben in "main" gezeigt, macht ?
    (Ob das jetzt gut oder schlecht ist sei mal dahingestellt.)

    Bzw

    int main()
    {
       adr adress* = new adr();
       // ...
       // hier passiert ganz viel 
       //
       delete adress;
       // ...
       // hier passiert ganz viel 
       //
       adress->del();
    
       retrun 0;
    }
    

    Nochmal ob das jetzt gut oder schlecht ist sei mal dahingestellt.

    Grüße



  • Nicht so ganz. Wenn du auf this == 0 testest, dann muss this auch 0 sein damit das true wird. C++ hat keine Ahnung ob ein Pointer gültig ist oder nicht.

    adr *adress;
    adress->del(); //adress ist höchstwahrscheinlich nicht 0, daher bringt der 0-Test nichts
    
    adr *adress = new adr;
    delete adress;
    adress->del(); //adress ist definitiv nicht 0, daher bringt der 0-Test nichts
    


  • beispiellos schrieb:

    In C++11 hat sich beides geändert. Nullzeiger-Dereferenzierung ist erlaubt, solange es eine prvalue bleibt (und nicht in decltype oder so auftritt).

    Erzähl mehr.



  • volkard schrieb:

    beispiellos schrieb:

    In C++11 hat sich beides geändert. Nullzeiger-Dereferenzierung ist erlaubt, solange es eine prvalue bleibt (und nicht in decltype oder so auftritt).

    Erzähl mehr.

    Puh, dann bin ich nicht der einzige der sich dumm vorkommt 🕶



  • Nexus schrieb:

    volkard schrieb:

    Ich fürchte, das muss man nur machen, wenn man das Gesamtkonzept verloren hat und versucht, Zugriffsfehler im Nachhinein an den Symptomen zu heilen.

    Sehe ich auch so. Generell halte ich die Notwendigkeit, Zeiger immer gleich sofort auf Null zu setzen (nach delete -- oder noch schlimmer -- im Destruktor) und jeweils zu prüfen, für fragwürdig. Oft ist das ein Hinweis darauf, dass man sich über die Gültigkeit seiner Zeiger nicht im Klaren ist.

    Auch wenn ich es ebenso sehe: Wenn man Altcode übernimmt, und nicht die Zeit für eine saubere Korrektur bekommt, ist so etwas dennoch ein Weg um Fehler zu finden.

    Ich habe mehr als einmal an einer "historisch gewachsenen" Anwendung gearbeitet, und nur in seltenen Fall (wie z.B. in meiner aktuellen Firma) erhält man auch die Zeit um Code wirklich zu korrigieren (selbst wenn man es wohl dennoch versucht, geht dies ansonsten nur immer Häppchenweise).

    Ich kenne Projekte bei dem ein Programmierchef der Meinung das alles möglichst public und static zu deklarieren und hat solche Variablen auch doppelt und dreifach zu verwenden. Und dies galt auch für Zeiger (wenigstens konnte man davon ausgehen das diese wenn Objekte gelöscht wurden sind genullt wurden, so das man diese gegen null prüfen konnte). Dies ganze wurde noch dadurch verschlimmbessert, dass der zudem die Meinung galt, das der Benutzer keine Fehlermeldungen sehen sollte (lieber mal auf gewissen Inkonsistenzen weiter arbeiten). Ich habe eines für mein Leben gelernt: Wenn ich jemals wieder an so ein Projekt komme werde ich aktiv umgehend eine neue Stelle suchen.



  • Ich meinte meine Aussage generell, nicht auf dd+ bezogen. Ja, Legacy-Code ist natürlich immer mühsam, aber ich habe Sachen wie SAFE_DELETE auch schon genügend oft in neuem Code gesehen.

    Ohnehin würde ich hier kein if verwenden, sondern assert (wenn ich mich in so einer Situation befände, normalerweise prüfe ich natürlich nicht auf this -Gültigkeit). Wobei das natürlich Projektmanagern, die lieber mit Fehler weiterarbeiten, nicht gefallen könnte...



  • Aber zur Sicherheit noch einen catch(...)-Block drumherum!



  • Decimad schrieb:

    Aber zur Sicherheit noch einen catch(...)-Block drumherum!

    Hier die Datei "IchBinEineWaschmaschine.hpp"

    #define main real_main
    #indlude "IchMagJava.hpp"
    

    Und die "IchBinEineWaschmaschine.cpp"

    int main() {
    	for(;;)
    		try {
    			int real_main();
    			return real_main();
    		} catch(...) {
    		}
    }
    


  • Nexus schrieb:

    Soweit richtig?

    Nein. Der Wert von t ist nach den Zuweisungen durch 0 , NULL und nullptr jeweils derselbe. Das Makro NULL ist in C++ gerade als 0 definiert, nullptr ist die typsichere C++11-Variante.[/quote]

    Ich nutze das mal als Gelegenheit eine Frage zu stellen:

    Was genau bringt "nullptr" für Vorteile gegenüber "NULL" oder "0" ? ( ist ernst gemeint ).



  • It0101 schrieb:

    Was genau bringt "nullptr" für Vorteile gegenüber "NULL" oder "0" ? ( ist ernst gemeint ).

    Irgendwie ist der Typ int da falsch.

    #include <iostream>
    
    char const* mySecret="geheim";
    
    template<typename T,typename U>
    bool test(T const t,U const u){
        return t==u;
    }
    
    int main() {
        using namespace std;
        if(mySecret==0)
            cout<<"no secret\n";
        if(test(mySecret,nullptr))
            cout<<"no secret\n";
        if(test(mySecret,0))//klappt seltsamerweise nicht
            cout<<"no secret\n";
    }
    

  • Mod

    Das hat diese Vorteile:
    1. Es hebt die Doppeldeutigkeit der 0 auf (auch wenn diese aus Gründen der Abwärtskompatibilität weiterhin besteht, so sollte aber doch zumindest in neuem Code mit 0 immer eine Integer-Konstante gemeint sein).
    2. nullptr ist von einem Pointertyp und somit nicht mehr in einen Ganzzahltyp (außer bool) konvertierbar.
    3. Noch schlimmer als 0 war NULL, da es sich so anfühlte, als hätte es die Vorteile 1 und 2, aber in Wirklichkeit war das gar nicht so, da NULL in C++ als 0 definiert ist. Daher war folgende verwirrende Überladungsauflösung möglich:

    void foo(int);
    void foo(void*);
    ...
    foo(NULL); // Ruft foo(int) auf
    

    Das kann mit nullptr nicht passieren.



  • Danke euch. Das leuchtet mir durchaus ein, wenngleich ich der Meinung bin, dass die Vorteile nicht ganz so groß sind, wie der Aufriss, der hier im Thread gemacht wird 😃



  • ...



  • It0101 schrieb:

    Das leuchtet mir durchaus ein, wenngleich ich der Meinung bin, dass die Vorteile nicht ganz so groß sind, wie der Aufriss, der hier im Thread gemacht wird 😃

    Ist das gleiche wie mit std::array oder RAII: Du hast Null Kosten, wenn du nullptr benutzt -- nur Vorteile. Es wäre dumm, bei einem C++11-kompatiblen Compiler noch 0 oder NULL für Zeiger einzusetzen.



  • It0101 schrieb:

    Danke euch. Das leuchtet mir durchaus ein, wenngleich ich der Meinung bin, dass die Vorteile nicht ganz so groß sind, wie der Aufriss, der hier im Thread gemacht wird 😃

    Jo, ich hatte noch nie einen Fehler wegen 0 zu suchen.
    Also der Aufriß im Sinne von "Nehmt sofort nurnoch nulltptr, sonst werden wir alle serben!" ist sicher übertrieben.
    Vielleicht folgt bald im Thread "Würdest Du an wirklich großen Projekten arbeiten, dann wärst Du meiner Meinung.". Dann wird es religiös.

    Aber da wir nullptr schonmal haben, sollte man ihn auch nehmen, weil kostet ja nix und könnte irgendwann mal ein Viertel Stündchen sparen.
    Öhm. Nö, dann muss man das Mehr an Tipparbeit rechnen und 0 ist besser.
    Anderer Grund: Man muss sich nullptr angewöhnen, weil sich die deutlich überwiegende Mehrheit der Gemeinde es auch angewöhnt. Dadurch kann man Fragen mit Querllcode posten, ohne daß der Thread reflexartig fünf bis acht wohlmeinende Hinweise auf nullptr fängt und die Hauptfrage fast untergeht.



  • Ich muss gar nichts. Ich arbeite mit memset, damit bin ich bei 90% der Member ohnehin unten durch. Den nullptr werde ich trotzdem verwenden, weil es ja in der Tat nichts kostet.



  • It0101 schrieb:

    Ich muss gar nichts. Ich arbeite mit memset, damit bin ich bei 90% der Member ohnehin unten durch.

    Jo. Das sagt, daß Du Dir seit Jahren Dein Compilat nicht mehr angeschaut hast.
    Der optimierende Compiler erkennt memsettende Schleifen von selber und optimiert genau gleich wie intrinsisches memset.



  • volkard schrieb:

    Also der Aufriß im Sinne von "Nehmt sofort nurnoch nulltptr, sonst werden wir alle serben!" ist sicher übertrieben.

    Solange ich mir aussuchen darf wo ich lebe werde ich auch Serbe.


Anmelden zum Antworten