auto_ptr



  • Der C++ Standard sagt:

    explicit auto_ptr(X* p =0) throw();
    

    somit darf foo nicht compilieren. Was compilieren dürfte wäre { return auto_ptr<X>(0);} was es zumindest unter gcc 4 auch tut und auch net segfaulted oder ähnliches.



  • Camper! So, habe mal deinen Beispielcode unter VC++ 7.1 ausprobiert. Ergebnis:

    error C2664: 'std::auto_ptr<_Ty>::auto_ptr(std::auto_ptr<_Ty> &) throw()': Konvertierung des Parameters 1 von 'int' in 'std::auto_ptr<_Ty> &' nicht möglich

    Hem, war wohl in 7.1 richtig und ist jetzt in 8.0 falsch? 🙄



  • PlasmaHH schrieb:

    Der C++ Standard sagt:

    explicit auto_ptr(X* p =0) throw();
    

    somit darf foo nicht compilieren.

    Warum darf es das nicht? 0 ist doch ein X* oder? IMHO sollte das schon kompilieren, nur crashen sollte es nicht.


  • Mod

    ich hab ja auch nicht gesagt, dass es compilieren darf, das ist nicht der fall. das problem bei vc8 ist, dass der konstruktor auto_ptr_ref einen generischen void* pointer nimmt und weder explicit nocht private ist. fügt man eines davon ein, ist dies problem gelöst (es ist bei mir aufgetaucht als ich code, der mit nakten pointern arbeitet, mit auto_ptr zwecks exceptionsicherheit aufgerüstet habe - gelegentlich übersieht man dabei solche return 0 - und erwartet nat. dass der compiler darauf hinweist). das problem mit den virtuellen basen löst es allerdings nicht.

    kleiner fehler übrigens oben, es muss heissen:

    template<typename Source>
        auto_ptr(auto_ptr< Source >& rhs ) throw()
            : ptr_( implicit_cast< Pointee*, Source* >( rhs.get() ) )
        {
            rhs.ptr_ = 0;
        }
        template<typename Source>
        auto_ptr& operator=(auto_ptr< Source >& rhs ) throw()
        {
            delete get();
            ptr_ = implicit_cast< Pointee*, Source* >( rhs.get() );
            rhs.ptr_ = 0;
            return *this;
        }
    

    wobei ich mir Stroustrup's implicit_cast geborgt habe:

    template<class T, class U> T implicit_cast(U u) { return u; }
    

    mit static_cast wären ja downcasts möglich.



  • Jester schrieb:

    PlasmaHH schrieb:

    Der C++ Standard sagt:

    explicit auto_ptr(X* p =0) throw();
    

    somit darf foo nicht compilieren.

    Warum darf es das nicht? 0 ist doch ein X* oder? IMHO sollte das schon kompilieren, nur crashen sollte es nicht.

    0 ist ein int, was aber egal ist; explizit heißt keine implizite typumwandlung (und die typumwandlung würde von X* nach auto_ptr<X> stattfinden)



  • nanunu schrieb:

    0 ist ein int, was aber egal ist

    Stimmt, im Großen und Ganzen hast Du recht. Aber 0 ist nicht nur ein int. 0 ist genausogut (leider) ein Pointer.



  • Jester schrieb:

    0 ist genausogut (leider) ein Pointer.

    Ansichtssache würde ich sagen. 😃
    Wie dem auch sei, alle Klarheiten beseitigt warum es nicht kompilieren darf ? 😮



  • Nicht ganz - 0 ist die Nullzeiger-Konstante, die implizit konvertierbar ist in einen Nullzeiger eines konkreten Typs :p


  • Mod

    noch eine kleine fehlerberichtigung: der schutz auf selbstzuweisung darf auch in der template version nicht fehlen, denn der user könnte diese version explizit aufrufen; analoges gilt für den operator=, der ein auto_ptr_ref nimmt.



  • 7H3 N4C3R schrieb:

    Nicht ganz - 0 ist die Nullzeiger-Konstante, die implizit konvertierbar ist in einen Nullzeiger eines konkreten Typs :p

    Richtig. Somit würde augenscheinlich der auto_ptr<X>( X* ) ctor passen. Dieser ist aber explizit markiert, und das zurückgeben von einem X*, wobei die Funktion einen auto_ptr<X> zurückgibt, würde implizit den auto_ptr<X>(X*) ctor aufrufen, was aber das explizit keyword verbietet. Ein

    return auto_ptr<X>(0);
    

    jedoch ruft diesen explizit auf, was auch ok ist.
    Ähnlich verhält es sich hier:

    X* x = ...; // beliebiger wert
    /*
    Produziert z.B. mit gcc richtigerweise einen fehler wie:
    error: conversion from ‘X*’ to non-scalar type ‘std::auto_ptr<X>’ requested
    */
    auto_ptr<X> Xa = x;
    /*
    So wirds gemacht:
    */
    auto_ptr<X> Xa(x); // oder
    auto_ptr<X> Xa = auto_ptr<X>(x);
    

    Was im übrigen auch sinn macht, denn wäre der ctor nicht explizit würde man oftmals mal gegen die Wand rennen, wenn so eine Konversion stattfindet und das Objekt einfach mal gelöscht wird.



  • Jester schrieb:

    Stimmt, im Großen und Ganzen hast Du recht. Aber 0 ist nicht nur ein int. 0 ist genausogut (leider) ein Pointer.

    Simmt, im Allgemeinen. Aber in diesem konkreten Fall muss 0 ein int sein, was zu einer Fehlermeldung à la "Konnte int nicht in auto_ptr<X> umwandeln" und sicher nicht zu einer Fehlermeldung "Konnte X* nicht in auto_ptr<X> umwandeln". Für die Konvertierung 0 -> X* gibt es hier kein Indiz.



  • nanunu schrieb:

    Jester schrieb:

    Stimmt, im Großen und Ganzen hast Du recht. Aber 0 ist nicht nur ein int. 0 ist genausogut (leider) ein Pointer.

    Simmt, im Allgemeinen. Aber in diesem konkreten Fall muss 0 ein int sein, was zu einer Fehlermeldung à la "Konnte int nicht in auto_ptr<X> umwandeln" und sicher nicht zu einer Fehlermeldung "Konnte X* nicht in auto_ptr<X> umwandeln". Für die Konvertierung 0 -> X* gibt es hier kein Indiz.

    Diese Konversion wird intern vom Compiler versucht, aber verworfen da sie nicht zu einem Ergebniss kommt. Daher wird der original Datentyp in der Fehlermeldung angegeben. Dies kann manchmal ähnlich verwirrend sein wie wenn man einen Pointer zu einem Typ hat, welcher von einer Basisklasse abgeleitet ist, und versucht den über einen solchen Basispointer weiterzugeben...


Anmelden zum Antworten