operator() const, mit einem iterator
-
Hallo,
Ich will mithilfe einer existierenden Library ("Eigen") ein Gleichungssystem loesen. (VectorXd &x sind die Variablen x, VectorXd &fvec sind die y)Dazu habe ich eine Klasse "Model" gemacht, in der der operator() definiert ist.
model.h int operator()(const Eigen::VectorXd &x, Eigen::VectorXd &fvec) const ; model.cpp int Model::operator()(const VectorXd &x, VectorXd &fvec) const { fvec[0]=x[0]-x[1]-x[2]; fvec[1]=100-(x[0]/7-3)*(x[0]/7-3); fvec[2]=(x[1]/20)*(x[1]/20)-(x[2]/25)*(x[2]/25); return 0; }Dieser Teil funktioniert auch praechtig.
Jetzt will ich aber x[..] und fvec[..] durch einen iterator definieren.
Ich dachte mir so:int Model::operator()(const VectorXd &x, VectorXd &fvec) const { std::list<Loop*>::const_iterator it = loopList_.begin(); int i = 0; for ( ; it != loopList_.end() ; ++it, ++i) { Loop* loop = *it; (*loop).setM(x[i]); } for ( it = loopList_.begin(), i = 0 ; it != loopList_.end() ; ++it, ++i) { Loop* loop = *it; fvec[i]=(*loop).getDP(); } }Funktioniert aber nicht, weil diese loopList_ durch einen anderen Teil im code erst generiert wird.
Am breakpoint des iterators sagt der Debugger immer: loopList_ <not accessible> ..
Ich habe die "const" im Verdacht, weiss aber nicht was zu tun ist.Wie wuerdet ihr weitermachen?
Danke
-
Falls das wirklich mit dem Debugger mittels eines Breakpoints ermittelt wurde, dann ist das ganz was anderes. In dem Fall würde ich auf einen Fehler durch die Zeigerei tippen. Mit const hätte es auf jeden Fall nichts zu tun. Aber wir bräuchten ein besseres Codebeispiel und eine bessere Fehlerbeschreibung ("funktioniert nicht"
). Siehe:
http://www.c-plusplus.net/forum/304133
-
Im Detail sieht der code so aus:
// main.cpp #include "afk.h" #include <iostream> #include <Eigen/Eigen> #include <unsupported/Eigen/NonLinearOptimization> using namespace std; using namespace Eigen; int main(int argc, char *argv[]) { int n = 2, info=-1; VectorXd x(n), fvec(n); x[0]=1.0; x[1]=3.14; AFK afk; afk.operator ()(x, fvec); }// afk.h #ifndef AFK_H #define AFK_H #include "model.h" class AFK : public Model { public: AFK(); }; #endif // AFK_H // afk.cpp #include "afk.h" #include "loop.h" #include "fluid.h" #include "tube.h" #include <list> using namespace std; AFK::AFK() { Fluid tw(Fluid::oil); Loop l1("loop1", tw), l2("loop2", tw); Tube t1(0.1, 100), t2(0.2,240), t3(0.15,100,10); l1.p(t1).p(t2); l2.n(t1).p(t3); addLoop(l1); addLoop(l2); }AFK ist ein Model, und im Model sind der operator() und die Methode "addLoop" definiert.
// model.cpp #include "model.h" #include "loop.h" #include <iostream> using namespace Eigen; using namespace std; Model::~Model(){} int Model::operator()(const VectorXd &x, VectorXd &fvec) const { const int n = x.size(); assert (fvec.size()==n); std::list<Loop*>::const_iterator it = loopList_.begin(); int i = 0; for ( ; it != loopList_.end() ; ++it, ++i) { Loop* loop = *it; (*loop).setM(x[i]); } for ( it = loopList_.begin(), i = 0 ; it != loopList_.end() ; ++it, ++i) { Loop* loop = *it; fvec[i]=(*loop).getDP(); } } int Model::inputs() const { return dimension_; } int Model::values() const { return dimension_; } void Model::addLoop(Loop& l){ loopList_.push_back(&l); }// model.h #ifndef MODEL_H #define MODEL_H #include <Eigen/Eigen> #include <list> class Loop; class Model { public: Model(int dimension = 2):dimension_(dimension){} virtual ~Model(); int operator()(const Eigen::VectorXd &x, Eigen::VectorXd &fvec) const ; int inputs() const; int values() const; void addLoop(Loop& l); private: int dimension_; std::list<Loop*> loopList_; }; #endif // MODEL_HIch verwende QT-Creator und kann den code compilieren. Wenn ich ohne breakpoint einfach starte, bekomme ich "The Program has unexpectedly finished".
Wenn ich in Zeile 18 von model.cpp einen breakpoint setze, sehe ich, dass loopList_ <not accessible> ist, obwohl sie vorher mit den beiden addLoop in afk.cpp "befuellt" wurde.Ich bin mit meinem Latein am Ende.

-
kwurpi schrieb:
Ich verwende QT-Creator und kann den code compilieren. Wenn ich ohne breakpoint einfach starte, bekomme ich "The Program has unexpectedly finished".
Wenn ich in Zeile 18 von model.cpp einen breakpoint setze, sehe ich, dass loopList_ <not accessible> ist, obwohl sie vorher mit den beiden addLoop in afk.cpp "befuellt" wurde.Das heißt bloß, dass du deinen Debugger irgendwie nicht richtig benutzt. Der kann die nötigen Informationen nicht finden, um dir genaue Meldungen zu machen.
Das Problem ist, wie schon vermutet, das Zeigergefrickel. Du hast deinen Container mit Verweisen auf lokale Variablen gefüllt, die beim Zugriff da drauf schon längst nicht mehr existieren. Warum Zeiger?
-
Sepp,
das liegt einfach daran, dass ich ein kompletter Anfaenger bin.
Ich will eigentlich gar keine Zeiger verwenden, sondern nur Referenzen.
Wo habe ich den Container mit Verweisen auf lokalen variablen gefuellt?
-
void Model::addLoop(Loop& l){ loopList_.push_back(&l); //Hier liest du nur die Adresse zu einer Klasse ein. }std::list<Loop*> loopList_; //Hier speicherst du nur AdressenVerbesserung:
loopList_.push_back(l); std::list<Loop> loopList_;
-
Ich wollte aber in loopList_ keine objects sondern nur references haben
Geht das so wie du beschrieben hast:loopList_.push_back(l); std::list<Loop> loopList_;
-
void Model::addLoop(Loop& l) //Hier verlangst du eine Referenz durch denn Operator & { loopList_.push_back(l); //Die Referenz wird nun in die Liste eingefügt }Ich denke mal du hast (&l) geschrieben weil du denkst dass das eine Refernz daraus macht?
Deine Referenz ist am ende nur eine Kopie der Klasse, diese Kopie wird am ende der eigentlichen Klasse zurück gegeben.
Der einzige Weg die Klasse selbst zu nutzen ist:
void Model::addLoop(const Loop& l){ loopList_.push_back(l); }Aber dann kann die Klasse auch nicht verändert werden.
-
ok, soweit kann ich dir folgen.
Aber brauch ich dann das:std::list<Loop> loopList_;oder
std::list<Loop&> loopList_;(Ich weiss, das sind wirklich beschaemend dumme Fragen.)
Danke
-
Ich wollte aber in loopList_ keine objects sondern nur references haben
Weshalb? Kopieroptimierung?
Es wäre unintuitiv (=falsch?) wenn man Referenzen an eine Funktion übergibt und diese nach ihrer Beendigung immernoch Seiteneffekte auf das Objekt hat.
Speichere die Objekte (bzw Kopien) besser in dem Vektor in der Klasse, wie exploit126 vorgeschlagen hat.
EDIT:
- Wenn es wirklich verweise auf die alten Objekte sein sollen (/müssen!), dann Zeiger als Funktionsparameter nehmen.
- Wenn du NICHT garantieren kannst, dass die Objekte deine Klasse komplett überleben, dann brauchst du shared ownership (shared_ptr)Aber! Wenn beides letzteres der Fall ist, dann kannst du bestimmt was an deiner Programmstruktur verbessern.
-
Nein, Kopieroptimierung ist mit erstmal egal.
Aber ich will, dass "setM" in Zeile 20 von model.cpp auf dem
uebergebenen Loop-object arbeitet, und nicht auf einer Kopie.geht das?
-
ich denke, dass in diesem Fall der shared_ptr ist was du willst, aber dann verpasst du deinen Loops die Eigenschaften von globalen Variablen. Jeder der ein Besitz von ihnen hat kann sie verändern.
EDIT: Das ist schwer zu debuggen und führt normalerweise eher zu Kopfschmerzen.EDIT 2: Die Frage ist, wo du deine loops speichern willst.
Momentan fügst du Zeiger auf lokale Objekte hinzu, die zerstört werden bevor du was mit ihnen machst.Deshalb läufst du in dein Problem.
-
Ich will eigentlich nur eine Liste der "Loop"s, die es im "Model" afk gibt.
Also Loop l1, und Loop l2 in einer Liste &l1, &l2.Ueber diese Liste will ich dann mit einem iterator in Model::operator()
iterieren. Dabei muss ich aber jede Loop mit "setM" veraendern. Ich kann also
nicht mit kopierten objects in loopList_ arbeiten.Kann man die Erklaerung verstehen?
Oder anders:
eine Loop ist eine Gleichung deren x-Wert mit "setM" gesetzt wird, und deren y-Wert mit "getDP" ausgelesen wird.
Und der operator() wird dann vom solver in Eigen immer wieder mit veraenderten x-Werten aufgerufen, bis die y-Werte alle Loops 0 werden.
-
Ok gut, dann schlage ich sowas vor:
class Model { //... gekürzt auf meine Änderungen public: void addLoop(Loop const& l); private: std::vector <Loop> loopList_; // es sei denn du hast einen guten Grund für die Liste (z.B. vieles entfernen und hinzufügen in der Mitte des Containers) }; // ... int Model::operator()(const VectorXd &x, VectorXd &fvec) /*EDIT: nicht const*/ { // ... // mit C++11 for (auto& it : loopList_) { it.setM(x[i]); } // mit C++98 for (std::vector <Loop>::iterator it = loopList_.begin(); it != loopList_.end(); ++it) { it->setM(x[i]); } //... } void Model::addLoop(Loop const& l) { loopList_.push_back(l); }nun kannst du Loops in das Model hinzufügen und mehrmals den Funktionsoperator aufrufen und jedes Mal werden die Loops, die in deinem Model gespeichert sind, geändert.
EDIT: habe deinen integer i vergessen. Deshalb habe ich oben nochmal die Namen korrigiert.
-
wow, da lieferst du mir ja die ganze Loesung.
Super!
Lass mich das ausprobieren.
-
Jetzt bekomme ich (mit der c++11 variante) beim compilieren:
passing 'const Loop' as 'this' Argument of 'void Loop::setM(float)' discards qualifier [-fpermissive]
-
Ja ich sehe gerade, dein Funktionsoperator ist const.
Dann kann er natürlich keine Member der Klasse verändern.
Ich hatte das dummerweise mitkopiert.
-
sieht gut aus!
Ich glaube damit ist dieses Problem geloest.
Was aber leider unweigerlich eine anderen Fehler offenlegt...
Da muss ich jetzt ran.
vielen Dank jedenfalls fuer deine Ausdauer!
kwurpi