Garbage Collector
-
Bald soll ja neues C++ raus kommen

Freu mich schon riesig drauf. Meinst da ist ein Garbage Collector mit drin ??
Soll einiges von boost übernommen werden habe ich gehört.
-
AlexanderKiebler schrieb:
Bald soll ja neues C++ raus kommen

Freu mich schon riesig drauf. Meinst da ist ein Garbage Collector mit drin ??Nein, es ist kein GC enthalten. Es ist zwar ein optionaler GC langfristig angedacht (aber einer nach der Art: entweder für das ganze Programm, oder garnicht), aber nicht mehr für den Standard.
Wobei ich unter C++ keinen GC verwenden würde (unabhängig davon, das ich GCs nicht ablehne, nur passt es nicht zur C++ Programmierung).
-
AlexanderKiebler schrieb:
Was ist denn so schlecht daran einfach new und delete zu überladen ??
Ist das geächtet wie goto ??Nein. Das zu Überladen ist schon ok.
Aber das, was Du vor hast, kann nicht rundum funktionieren. Du wirst eine Frickellösung erhalten, die immer mit massig Ausnahmen une Einschränkungen leben muß. Große Kosten, aber praktisch kein Zugewinn. Zum Beispiel habe ich eine Klasse Button, die hat innendrin einen Zeiger auf das ihn besitzende Window. Im Button-Destruktor wird dem Window noch schnell bescheid gesagt. Vergißt der User, den Button zu löschen, ist das ein Fehler und der User muß bestraft werden.
Bei Dir hingegen wird der Button dann einfach nach der main gelsöcht, aber oh weh!, das Window ist ja schon lange weg und Du sagst totem Speicher bescheid. Das ist Abstürzen auf die umständliche Art.Mach doch statt dem Aufräumer einen Auflister! Der Listet alle Speicherbereiche auf, die zu löschen vergessen wurden! Der User muß dann halt sein Speicherloch suchen und dichtmachen.
-
AlexanderKiebler schrieb:
Läuft einwandfrei muss ich sagen.
Bei dir laufen gar keine Destruktoren. Du nimmst den Objekten einfach den Speicher weg, ohne sie zu "destruieren". Bei PODs kann man das so machen. Aber auch nur dann. Das hier klappt schon nicht mehr:
struct ich_bin_kein_pod { std::string name; int geburtsjahr; };und Du bekommst Speicherlecks ohne Ende.
Ich sehe -- wie jemand vorher auch schon erwähnt hat -- keine Notwendigkeit hier mit Überladung von new/delete "rumzufrickeln". Du leitest ja eh zu dem Zweck von einer Klasse ab. Und diese Klasse könnte ebenso gut im Konstruktor und Destruktor sich "irgendwo" anmelden und abmelden. Ein virtueller Destruktor ist da wahrscheinlich auch nicht verkehrt.
Hier eine Skizze:
#include <cassert> #include <utility> #include <type_traits> #include <boost/noncopyable.hpp> struct links : private boost::noncopyable { links* prev; links* next; links() : prev(0), next(0) {} void isolate() { if (prev) prev->next = next; if (next) next->prev = prev; prev = next = 0; } ~links() {isolate();} }; void insert_after(links & l1, links & l2) { assert(!l2.prev); assert(!l2.next); l2.next = l1.next; if (l1.next) l1.next->prev = &l2; l2.prev = &l1; l1.next = &l2; } class collectable : links { friend class collector; protected: collectable() {} public: virtual ~collectable() {} bool owned() const {return prev;} void break_free() {this->isolate();} }; class collector : links { public: template<class T, class...Args> typename std::enable_if<( std::is_convertible<T*,collectable*>::value), T* >::type cnew(Args&&...args) { T* p = new T(std::forward<Args>(args)...); collectable* q = p; insert_after(*this,*q); return p; } void take_over(collectable* t) { t->isolate(); insert_after(*this,*t); } ~collector(); }; collector::~collector() { while (next) { collectable* const tmp = static_cast<collectable*>(next); delete tmp; // <-- mutates next assert(next != tmp); } } #include <iostream> struct foo : collectable { int number; explicit foo(int i) : number(i) {} ~foo() {std::cout << "~foo, " << number << '\n';} }; int main() { collector c; foo* p = c.cnew<foo>(23); foo* q = c.cnew<foo>(1729); foo* z = new foo(42); c.take_over(z); delete p; // fine, Objekt is removed from c's list collector d; d.take_over(q); // steals *q from collector c } // <-- *q and *z will be destroyed hereDie Objekte, auf die p und q ind z zeigen "gehören" höchstens einem "Collector". Man kann sie manuell löschen oder von den Collectoren löschen lassen, wenn die Collectoren zerstört werden.
So etwas ähnliches machen die glaub'ich auch bei Qt -- also eine beidseitige Registrierung zwischen Besitzer und Besitz, so dass ein manuelles Löschen beim Besitzer auch automatisch gemeldet wird.
BTW: C++0x bringt von Haus aus keine Garbage-Collection mit.
kk
-
Ja das war auch mein erstes Mako was mit aufgefallen ist.
Denke ich kann den Destuktor aufrufen in dem ich
den GaCo destuktor virtuel mache, und bei der zerstörfunktion die entsprechenden deletes aufrufe. Bin aber gard noch dabei.Gruß
-
Kannst Dir ja mal mein Beispiel näher angucken. Das einzige, was ich anders mache und nicht deinem Plan entspricht ist, dass ich kein Singleton hier verwende sondern verschiedene "Collectoren" zulasse und ein Objekt, was ich per new erzeuge gehört auch nicht sofort einem Collector (welchem denn?). Das kannst Du natürlich anpassen und mit einem Singleton machen. Allerdings sehe ich den Sinn darin nicht ganz; denn damit würdest Du wirklich bis zum Programmende warten, um "aufzuräumen". Dann kannst Du es dir auch gleich fast sparen.
-
Also erstmal danke für deinen Quellcode.
Werd ihn mir mal genauer anschauen, aber das wird wieder etwas Zeit benötigen.
Kann mich mit boost noch nicht so gut aus, werd also die Klassen wo du von abgeleitet hast nachlesen müssen.
Schaut aber interessant aus was du dam machst.
Professioneller als mein Ansatz in jedem Fall =).
-
Ableiten von boost::noncopyable verhindert nur compiler-generierte Kopierkonstruktoren und Zuweisungsoperatoren. Sonst passiert da nichts.
Und sonst habe ich für das cnew template noch von C++0x Mitteln Gebrauch gemacht (Rvalue-Referenzen, Variadische Templates, Type Traits). Aber
foo* p = c.cnew<foo>(23);ist nur eine Abkürzung für
foo* p = new foo(23); c.take_over(p);kann man also auch weglassen.
-
AlexanderKiebler schrieb:
Also zunächst bleib ich dem verhalten von C++ treu, soweit es ein GUI programmierer kennt. Das passt eigentlich schon.
Der Programmierer Darf zerstören, muss aber nicht, so wie in den Meißten Bibliotheken.WTF???
Klar muss er, wer soll denn sonst, so lange keine Smart-Pointer im Spiel sind?
-
Na ja Also die QT baut ja einen Abhängigkeitsbaum auf.
Die mit new erzeugten Objekte werden dann automatisch vom Speicher genommen.
Man kann das Nachvollziehen, wenn man die destruktoren impelemntiert.So war das gemeint. Bei reinem C/C++ muss er natürlich....
Und bei der QT wird auch zerstört, aber eben automatisch.Habe aber noch ein anderes Problem.
Ich habe den Operator
void operator delete[] (void * ptr);überladen.
Leider wird beidelete[] *instances_arr_it;leider der operator
void operator delete (void * ptr);aufgerufen, was zu einem Speicherabsturz führt.
Woran liegt denn das ??
*instances_arr_it ist vom Typ const GaCo *Gruß
-
AlexanderKiebler schrieb:
Woran liegt denn das ??
lies mal ein anfängerbuch.
-
Keine Lust mir weiter zu helfen ??

-
AlexanderKiebler schrieb:
Und bei der QT wird auch zerstört, aber eben automatisch.
Nein, nicht automatisch! Parents löschen ihre children. Wenn du das Toplevel-parent nicht löschst, werden auch die children nicht gelöscht. Und das Verhalten ist nachvollziehbar und vom Benutzer durchschaubar und vor allem kontrollierbar - vor allem hier aber notwendig, denn bei verschachtelten Fensterlayouts wird es müßig, ständig beim Zerstören selber rekursiv über alle children zu iterieren und zu löschen - und am Ende gehts doch schief

Wenn hingegen einem einfach automatisch ohne Kontrolle das Objekt unterm Hintern weggerissen wird, kann das böse enden.
-

Ja da hat du Recht, es wird nicht selten vergessen das Top-level Parent zu löschen.Keine Angst ich ziehe niemandem Speicher unter der Nase weg. Das passt schon so bei mir, es ist sinnvoll und keine schlechte Idee. Das liegt am Komzept und an der Natur der Sache.
Ich kann dafür garantieren, dass die Objekte nicht mehr benötigt werden, wenn ich zum löschen anfange.
Und aus der Selben Motivation-- es wäre müßig und immer das Selebe -- lösche ich auch.Würde mich aber über eine Antwort wegen dem delete[] operator freuen.
Habe gelesen dass die new und delete operatoren sowei new[] und delete[]
gerne kompilerabhängige optionen haben......Gruß
-
Wieso klammerst du dich an die operator new/...-Überladung. Erstell dir eine Simulator-Klasse, der du Simulationen hinzufügen kannst. Biete eine Simulator::clear()-Methode an, welche alle Simulationen löscht. ~Simulator ruft natürlich auch clear() auf. Sorge dafür, dass das Simulator-Objekt garantiert spätestens bei Programmende zerstört wird. Punkt. Mehr brauchts doch nicht, oder?
Die Lösung von Krümelkacker ist sicherlich auch sehr schön, aber in meinen Augen für dich auch nicht unbedingt nötig.
Wenn es dir um das Verstehen von operator new/...-Überladung geht, dann ist das das falsche Beispiel.Wg. Placement-new: die STL-Container verwenden AFAIK gerne mal Placement-new, wenn speicher zwar mit reserve angefordert wurde (oder Speicher von einem vorherigen remove() frei geworden ist), aber die einzelnen Elemente noch nicht initialisiert wurden. Sobald du deine Collactable-Objekte in einem (z.B.) vector ablegst, wirst du über das ein oder andere Placement-new stolpern.
-
Okay, das klingt jetzt schon einleuchtender. Danke für das Argument.
Ich hätte ein Problem mit der STL innerhalb der von GaCo abgeleiteten Klassen.
Oder ich müßte placement new überladen.
Kann man das nicht irgendwie mit::new ....delegieren ??
Also zunächst klammere ich mich da dran, weil ich mich dafür schon sehr interessiere, auch wenn es ier nicht die beste Lösung ist.
Kannst du mir ne Seite Sagen, wo new new[] delete und delete[] exakt beschrieben werden.
Wenn ich merke dass ich damit nicht zurecht komme, werde ich es wie empfohlen anderst machen. Trotzdem glaube ich sollte ich mich irgendwann auch mit den Operatoren zum Speicheranfordern genauer auseinandersetzen.
Ich halte das einfach für wichtig.Gruß
-
AlexanderKiebler schrieb:
Na ja Also die QT baut ja einen Abhängigkeitsbaum auf.
Die mit new erzeugten Objekte werden dann automatisch vom Speicher genommen.
Man kann das Nachvollziehen, wenn man die destruktoren impelemntiert.So war das gemeint. Bei reinem C/C++ muss er natürlich....
Und bei der QT wird auch zerstört, aber eben automatisch.Dann darf er aber nicht mehr.
"Darf, muss aber nicht" gibt's in C++ üblicherweise einfach nicht.
-
Magst mir nicht ein gutes Beispiel zum Überladen von new und delete zeigen, wo ich schön lernen kannHäuptling hustender Bär *ggg*
Arbeitest du bei den Licht Tools mit da du für sie wirbst *lach*
Woher hast denn das ??Das Problem ist, ich interessiere mich echt dafür. So wie ich mich kenne werde ich immer wieder new und delete überladen wollen, solange bis ichs kann, und es uninteressant wird
weils bessere lösungen gibt.
-
AlexanderKiebler schrieb:
Arbeitest du bei den Licht Tools mit da du für sie wirbst *lach*
Woher hast denn das ??Ist ein Projekt eines Freundes von mir. Ich hab nur den native Win32 C++ Port gemacht.