STL vector vs. array of pointers
-
Da dich eh gleich jemand darauf hinweisen würde ...
// Move-Assignment: *this zerstoeren, danach wie Move-Konstruktor Dummy& operator = (Dummy&& other) { if(stuff_) gsl_free_stuff(stuff_); stuff_ = other.stuff_; other.stuff_ = nullptr; return *this; }Hier fehlt ein
if(this == &other) return *this;
-
Hallo Kellerautomat,
vielen Dank für deine ausführliche Antwort und das Beispiel.
Ich habe das versucht umzusetzen (siehe unten) auf mein obiges Beispiel und ich bin platt: Es funzt!!

- Im nächsten Schritt werde ich versuchen die Methode auf die Verwendung der GSL zu übertragen.
- Natürlich hast du recht, dass es besser ist einen getesteten Wrapper zu verwenden. Aber ich habe den Eindruck, dass ein Wrapper genau das tut, was ich gerade lerne. Und so lange ich das nicht richtig verstehe ist es sicherlich ebenso fahrlässig einen Wrapper einzusetzen.

- Leider erlaubt mein
gcccompiler keine Verwendung vonnullptr, da dies laut google erst abgcc4.6 möglich ist, ich unter Debian Squeeze abergcc4.4.5 habe. Ich hoffe eine '0' einzusetzen ist auch okay.
Ethon schrieb:
Hier fehlt ein
if(this == &other) return *this;Wie meinen? Wenn ich die if-Abfrage einbaue, dann habe ich sowohl in der if-Abfrage als auch 'normal' ein
return *this.
Wenn ich die if-Abfrage anstatt des return statements einbaue, dann kann es sein, dass ich nichts zurückgebe, falls die if-Abfrage false liefert?Viele Grüße,
-- Klaus.// dummy.cpp #include <iostream> #include <vector> using std::cout; using std::endl; using std::vector; using std::move; struct dummy { dummy() : val(42) {} unsigned int val; }; struct foo { // Konstruktor foo() : d_(new dummy) {} // Move-Konstruktor foo(foo&& other) : d_(other.d_) { other.d_ = 0; } // Move-Zuweisungsoperator foo& operator=(foo&& other) { if(d_) delete d_; d_ = other.d_; other.d_ = 0; return *this; } // Destruktor ~foo() { if(d_) delete d_; } struct dummy* d_; }; int main() { vector<struct foo> foos; foos.push_back(move(foo())); cout << foos[0].d_->val << endl; return 0; }
-
Klaus82 schrieb:
Tada!! Fertig. Kein Speicherzugriffsfehler, kein Memory-Leak, kein gar nichts.
Gib mal ein
bar-Objekt aus einer Funktion zurück, dann reden wir weiter. Dein Design ist eine tickende Zeitbombe.Ethon schrieb:
Da dich eh gleich jemand darauf hinweisen würde
Oder man macht es direkt mit Copy-and-Swap...
-
using std::cout; using std::endl; using std::vector; using std::move; // Würde ich nicht kategorisch machen, das hebelt den Sinn von Namensräumen aus // und macht schlechter erkennbar, dass es sich um die Standardbibliothek handelt foo(foo&& other) : d_(other.d_) { other.d_ = 0; } // Nimm nullptr für Nullzeiger-Konstanten if(d_) delete d_; // delete auf Nullzeiger ist erlaubt (kein Effekt) d_ = other.d_; other.d_ = 0; return *this; // schau dir mal Copy-and-Swap an. Eine swap()-Funktion kann auch sonst nützlich // sein, und damit wird die Implementierung trivial. struct dummy* d_; vector<struct foo> foos; // struct bei der Variablendeklaration ist in C++ unnötig und unüblich. foos.push_back(move(foo())); // Das std::move() ist unnötig, du hast bereits einen RValue. // Lies dich in Move-Semantik ein, z.B. die Artikelserie auf C++Next // http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/Aber du baust dir mit
fooohnehin nur einen limitiertenstd::unique_ptrnach, dann kannst du gleich letzteren verwenden. Kellerautomats Hinweis war für andere Ressourcen gedacht, wo nicht nur Speicher verwaltet werden muss.
-
...
-
Nexus schrieb:
foo(foo&& other) : d_(other.d_) { other.d_ = 0; } // Nimm nullptr für Nullzeiger-Konstanten if(d_) delete d_; // delete auf Nullzeiger ist erlaubt (kein Effekt) d_ = other.d_; other.d_ = 0; return *this;Siehe meine Aussage dazu oben:
Klaus82 schrieb:
- Leider erlaubt mein
gcccompiler keine Verwendung vonnullptr, da dies laut google erst abgcc4.6 möglich ist, ich unter Debian Squeeze abergcc4.4.5 habe. Ich hoffe eine '0' einzusetzen ist auch okay.
Nexus schrieb:
Aber du baust dir mit
fooohnehin nur einen limitiertenstd::unique_ptrnach, dann kannst du gleich letzteren verwenden. Kellerautomats Hinweis war für andere Ressourcen gedacht, wo nicht nur Speicher verwaltet werden muss.Ich muss das alles erstmal verdauen. Ich bin fern davon zu behaupten, ich hätte was kapiert, sondern bestenfalls verstanden was das Problem ist: Dass ich den Speicherbereich eines Pointers nicht zwei Mal freigeben kann, im Objekt und dessen Kopie, leuchtet mir ein.
Die ganzen Details und cool Features mit den vielen Schlagwörten, die in diesem und dem anderen Thread gefallen sind muss ich mir nach und nach erarbeiten.
Jetzt funzt es auch mit der GSL, siehe unten!

Viele Grüße und noch ein schönen Restpfingstmontag,
-- Klaus.// mb.cpp #include <iostream> #include <vector> #include <gsl/gsl_errno.h> #include <gsl/gsl_spline.h> using namespace std; struct foo { void build (unsigned int const); void clean_up(); vector<double> x_values; vector<double> y_values; }; void foo::build(unsigned int const m) { for(unsigned int i = 0; i < 100; ++i) { x_values.push_back(i); y_values.push_back(m*i); } } void foo::clean_up() { x_values.clear(); y_values.clear(); } struct bar { // Default Konstruktor bar() : acc(0), spline(0) {} // Konstruktor bar(std::vector<double> &,std::vector<double> &); // Move-Konstruktor bar(bar&& other) : acc(other.acc), spline(other.spline) { other.acc = 0; other.spline = 0; } // Move-Zuweisungsoperator bar& operator=(bar&& other) { if(acc) gsl_interp_accel_free(acc); if(spline) gsl_spline_free(spline); acc = other.acc; spline = other.spline; other.acc = 0; other.spline = 0; return *this; } ~bar(); vector<double> x_values; vector<double> y_values; double get(double); gsl_interp_accel* acc; gsl_spline* spline; }; bar::bar(std::vector<double> & x, std::vector<double> & y): x_values(x), y_values(y), acc(gsl_interp_accel_alloc()),spline(gsl_spline_alloc(gsl_interp_cspline,x_values.size())) { gsl_spline_init(spline,& x_values.front(),& y_values.front(),x_values.size()); } bar::~bar() { gsl_interp_accel_free(acc); gsl_spline_free(spline); } double bar::get(double x) { return gsl_spline_eval(spline,x,acc); } int main() { vector<bar> bars; foo f; f.build(1); bars.push_back(move(bar(f.x_values,f.y_values))); f.clean_up(); f.build(2); bars.push_back(move(bar(f.x_values,f.y_values))); f.clean_up(); cout << bars[0].get(3.5) << endl; cout << bars[1].get(3.5) << endl; return 0; }
- Leider erlaubt mein
-
Hallo,
ich habe dazu mal wieder eine Frage:
Wenn ich ganz am Ende des obigen Codes noch eine weitere Zeile einfüge, weil ich z.B. eine Ausgabe haben möchte:
cout << bars[0].x_values.size() << endl;Dann kriege ich als Ergebnis eine satte Null!

Aber wie kann das sein? Wenn der Vektor der x- und y-Werte leer wäre, dann könnte die GSL doch gar keinen Wert interpolieren?
Oder hängt das damit zusammen, dass ich zwar im Konstruktor mittelsx_valuesundy_valuesden Spline für die Interpolation erstelle, aber dann nur noch diesen mittels move-Konstruktor weitergebe?Gruß,
-- Klaus.
-
Klaus82 schrieb:
Oder hängt das damit zusammen, dass ich zwar im Konstruktor mittels
x_valuesundy_valuesden Spline für die Interpolation erstelle, aber dann nur noch diesen mittels move-Konstruktor weitergebe?Genauso hast Du es doch geschrieben. Die Daten kommen in der Folge nur noch aus dem
gsl_splineObjekt.
Ich verstehe die Frage nicht.
-
Hallo Furble Wurble,
Furble Wurble schrieb:
Klaus82 schrieb:
Oder hängt das damit zusammen, dass ich zwar im Konstruktor mittels
x_valuesundy_valuesden Spline für die Interpolation erstelle, aber dann nur noch diesen mittels move-Konstruktor weitergebe?Genauso hast Du es doch geschrieben. Die Daten kommen in der Folge nur noch aus dem
gsl_splineObjekt.
Ich verstehe die Frage nicht.
Ja, aber jetzt würde ich gerne noch den Fall einbauen, dass der zu interpolierende Wert nicht in dem Bereich liegt, den ich zur Interpolation vorgebe:
double bar::get(double x) { if(x <= x_values.front() || x >= x_values.back()) return 0.0; return gsl_spline_eval(spline,x,acc); }Nur wenn dann
x_valuesnicht mehr existiert, dann habe ich ein Problem.
EDIT:
Also ich habe den default konstruktor, konstruktor und move konstruktor um folgende Zeilen ergänzt: Jetzt scheint es zu funktionieren:double const x_min; double const x_max; /* ---{}--- default constructor ---{}--- */ x_min(0),x_max(0) /* ---{}--- constructor ---{}--- */ x_min(x_values.front()),x_max(x_values.back()) /* ---{}--- move constructor ---{}--- */ x_min(other.x_min),x_max(other.x_max)Gruß,
-- Klaus.
-
Du kommst an die Daten natürlich auch über das
gsl_splineObjekt:double bar::get(double x) { if(x <= spline->x[0] || spline->x[spline->size-1] <= x) return 0.0; return gsl_spline_eval(spline,x,acc); }Schön ist was anderes...
Das mit den Vektoren, die einfach fallen gelassen werden beim moven ist auch Mist. Grübel nochmal über Dein Design.
Zumindest sollte immer gewährleistet sein, dass dasgsl_splineObjekt und dasbarObjekt Ihre Daten synchron halten - besser noch es gibt nur eine Kopie der Daten.Dein Edit habe ich mir nicht angesehen - scheint aber auch nicht an meinen Kritikpunkten anzusetzen.