Casten



  • Ich habe folgenden Code

    SmartPtr<TNLP> mynlp = new KRR_IPOpt( a, K, Ytrain, lambda );
    ...
    status = app->OptimizeTNLP( mynlp );
    ...
    for( int i = 0; i < a.n_rows; ++i )
    	a(i,0) = (*mynlp).a(i,0);
    

    KRR_IPOpt sieht so aus (Auszug aus dem Header):

    ...
    class KRR_IPOpt : public TNLP
    {
    	public:
    	mat K;
    	vec a;
    ...
    

    Wenn ich jetzt kompiliere erhalte ich folgende Fehlermeldung, die ja auch Sinn macht.

    KRR.cpp: In member function ‘void KRR::runOptimization()’:
    KRR.cpp:92:21: error: ‘class Ipopt::TNLP’ has no member named ‘a’
    make: *** [KRR.o] Error 1

    Wie komme ich durch korrektes casten an die eigentliche Variable ran?



  • Es sieht alles etwas kyptisch aus aber wenn ich dich richtig verstanden habe dann so:

    dynamic_cast<KRR_IPOpt*>(mynlp);
    


  • EOutOfResources schrieb:

    Es sieht alles etwas kyptisch aus aber wenn ich dich richtig verstanden habe dann so:

    dynamic_cast<KRR_IPOpt*>(mynlp);
    

    Vermutlich eher (je nach dem wie es bei dieser Smartpointerklasse heißt:

    dynamic_cast<KRR_IPOpt*>(mynlp.get());
    

  • Mod

    asc schrieb:

    EOutOfResources schrieb:

    Es sieht alles etwas kyptisch aus aber wenn ich dich richtig verstanden habe dann so:

    dynamic_cast<KRR_IPOpt*>(mynlp);
    

    Vermutlich eher (je nach dem wie es bei dieser Smartpointerklasse heißt:

    dynamic_cast<KRR_IPOpt*>(mynlp.get());
    

    Besser noch: gar nicht erst Typinformationen verlieren (unter der Annahme, dass der Smartpointer etwas taugt und automatische Konvertierungen in SmartPointer auf Basisklassen zulässt).

    SmartPtr<KRR_IPOpt> mynlp = new KRR_IPOpt( a, K, Ytrain, lambda );
    ...
    status = app->OptimizeTNLP( mynlp );
    ...
    for( int i = 0; i < a.n_rows; ++i )
        a(i,0) = (*mynlp).a(i,0);
    


  • Was camper vorgeschlagen hat, hatte ich auch schon probiert, dann erhalte ich allerdings eine andere Fehlermeldung:

    KRR.cpp:84:36: error: no matching function for call to ‘Ipopt::IpoptApplication::OptimizeTNLP(Ipopt::SmartPtr<KRR_IPOpt>&)’
    /homes/numerik/lib/Ipopt/include/coin/IpIpoptApplication.hpp:79:37: note: candidate is: virtual Ipopt::ApplicationReturnStatus Ipopt::IpoptApplication::OptimizeTNLP(const Ipopt::SmartPtrIpopt::TNLP&)
    make: *** [KRR.o] Error 1

    Trotzdem vielen Dank für die Hinweise von Euch. Im Header von SmartPtr habe ich nämlich die Methode GetRawPtr() gefunden und meinen Code entsprechend geändert:

    a(i,0) = dynamic_cast<KRR_IPOpt*>( GetRawPtr(mynlp) )->a(i,0);
    

    Jetzt funktionierts. 👍



  • Seltsamer Smartpointer... Wer hat den gemacht?



  • Das Problem ist das übliche bei Smartpointern und Ableitungen vom Zieltyp: ein smartpointer<Derived*> lässt sich nicht so einfach automatisch in einen Smartpointer<Base*> umwandeln.


  • Mod

    pumuckl schrieb:

    Das Problem ist das übliche bei Smartpointern und Ableitungen vom Zieltyp: ein smartpointer<Derived*> lässt sich nicht so einfach automatisch in einen Smartpointer<Base*> umwandeln.

    Ich habe es bisher für üblich gehalten, dass ein smartpointer diese Konvertierung anbietet. Ist ja auch so gut wie immer sehr simpel zu implementieren.
    auto_ptr hat diesbzgl. ein Problem, weil es mit den nötigen Tricks kollidiert, die die Movesemantik zu implementieren; aber einen "normalen" Smartpointer trifft diese Problematik nicht.
    Im konkreten Falle würde ich es allerdings noch etwas anders machen:

    KRR_IPOpt* mynlp = new KRR_IPOpt( a, K, Ytrain, lambda );
    SmartPtr<TNLP> mynlp_smart = mylnp;
    ...
    status = app->OptimizeTNLP( mynlp_smart );
    ...
    for( int i = 0; i < a.n_rows; ++i )
        a(i,0) = (*mynlp).a(i,0);
    

    Zumindest sollte es ein static_cast sein. dynamic_casts sind langsam und in diesem Falle logisch fragwürdig. Wir wissen in diesem Falle ja, dass es sich um ein KRR_IPOpt-Objekt handelt.

    Ansonsten empfehle ich noch einen Bug-Report an Ipop - habe mir mal kurz die Quellen angeschaut: sieht nicht so aus, als ob Konvertierungen zu irgenwelchen Schwierigkeiten führen würden.
    Edit: SmartPtr ist offenbar ein intrusive pointer, also get auch so etwas:

    SmartPtr<KRR_IPOpt> mynlp = new KRR_IPOpt( a, K, Ytrain, lambda );
    SmartPtr<TNLP> mynlp_ = GetRawPointer( mynlp );
    ...
    status = app->OptimizeTNLP( mynlp_ );
    ...
    for( int i = 0; i < a.n_rows; ++i )
        a(i,0) = (*mynlp).a(i,0);
    

    Wobei ich das für schlechten Stil halte. Der Sinn von intrusive Pointer liegt eigentlich nicht darin, dass man nach Belieben nackte und SMartpointer mischen kann.


Anmelden zum Antworten