Garbage Collection



  • HeXor schrieb:

    in *.hpp

    fastjet::ClusterSequence _cluster;
    

    Globale Variable im Header? Bitte nicht.
    Davon abgesehen hast du uns nicht den Code gezeigt, der den Fehler erzeugt, sondern nur einen Teil davon. Ohne compilierfähiges minimales Beispiel kann man dir da nicht so recht helfen.

    Davon abgesehen: Was möchtest du erreichen?


  • Mod

    Hast du selber einen operator= überladen? Falls ja, dann achte mal auf const-correctness.



  • pumuckl schrieb:

    HeXor schrieb:

    in *.hpp

    fastjet::ClusterSequence _cluster;
    

    Globale Variable im Header? Bitte nicht.
    Davon abgesehen hast du uns nicht den Code gezeigt, der den Fehler erzeugt, sondern nur einen Teil davon. Ohne compilierfähiges minimales Beispiel kann man dir da nicht so recht helfen.

    Davon abgesehen: Was möchtest du erreichen?

    Das ist eine Member Variable meiner Klasse in dessen Header file, also eingebettet in

    class MyTool {
      public:
      fastjet::ClusterSequence _cluster;
    }
    


  • HeXor schrieb:

    Das ist eine Member Variable meiner Klasse in dessen Header file, also eingebettet in

    Merkst was? Anhand deiner bisherigen Codefetzen kann man nichtmal annähernd erahnen, was du wirklich machst, geschweige denn dass man die Ursache des Fehlers erkennt.

    pumuckl schrieb:

    Ohne compilierfähiges minimales Beispiel kann man dir da nicht so recht helfen.

    Davon abgesehen: Was möchtest du erreichen?



  • pumuckl schrieb:

    HeXor schrieb:

    Das ist eine Member Variable meiner Klasse in dessen Header file, also eingebettet in

    Merkst was? Anhand deiner bisherigen Codefetzen kann man nichtmal annähernd erahnen, was du wirklich machst, geschweige denn dass man die Ursache des Fehlers erkennt.

    pumuckl schrieb:

    Ohne compilierfähiges minimales Beispiel kann man dir da nicht so recht helfen.

    Davon abgesehen: Was möchtest du erreichen?

    Ich hatte in den vorherigen Beispielen sehr genau klar gemacht was ich wollte, eine Member Variable eienr Klasse initialisieren (siehe meine vorherigen posts) sodass ich dachte jetzt den ganzen kram drum herum weg lassen zu können...

    Ein Minimalbeispiel habe ich soweit ich konnte gegeben, den eigentlichen Fehler in einem Minimalbeispiel zu reproduzieren ist schwierig, da ich hier einige Klassen importiere (fastjet klasse) mit weiteren abhängigkeiten, da sich dieses wie gesagt in einem größeren Framework befindet.

    Ich habe versucht diese Implementierung:

    Deklaration als Membervariable in *.hpp:
     fastjet::ClusterSquenece *_cluster;
    
    Implementation_1 in Funktion der Klasse in *.cpp:
     _cluster = new fastjet::ClusterSequence(_pseudoJets, _jetDef);
    

    Auf eine OHNE Pointer umzubauen:

    Deklaration als Membervariable in *.hpp:
     fastjet::ClusterSquenece _cluster;
    
    Implementation_1 in Funktion der Klasse in *.cpp:
     _cluster = fastjet::ClusterSequence(_pseudoJets, _jetDef);
    

    Und bekomme die obige Fehlermeldung. Folgendes funktioniert:

    Deklaration als Membervariable in *.hpp: 
    fastjet::ClusterSquenece _cluster;
    
    Implementation_1 in Funktion der Klasse in *.cpp:
     fastjet::ClusterSequence tmp(_pseudoJets, _jetDef);
    _cluster = tmp;
    

    Hoffe das ist verständlich, wenn nicht lasst es mich wissen...



  • Aus der Fehlermeldung lese ich, dass du einen

    ClusterSequence& operator=(ClusterSequence&);
    

    in der Klasse fastjet::ClusterSequence deklariert hast. Temporäre Objekte lassen sich nicht an non-const-Referenzen binden, und der benutzerdefinierte operator= verhindert die Generation eines Default-Operators.

    Was du eigentlich willst, ist ein

    ClusterSequence& operator=(ClusterSequence const &);
    

    Dass Objekte in C++ keine Referenztypen sind, ist dir bekannt?

    Ich vermute aber, dass das grundlegende Problem tiefer geht und du eigentlich keine Funktionen foo und finalize willst, sondern Konstruktoren und Destruktoren. "finalize" ist in C++ kein spezieller Funktionsname wie in Java, und das Hantieren mit halbfertigen Objekten ist problematisch - letzteres gilt nicht nur für C++.

    Kann es sein, dass du eigentlich

    class MyClass {
    public:
      MyClass(foo_t const &pseudo_jets, bar_t const &jet_defs);
      ~MyClass();
    
    private:
      fastjet::ClusterSequence cluster_;
    };
    
    MyClass:MyClass(foo_t const &pseudo_jets, bar_t const &jet_defs)
      : cluster_(pseudo_jets, jet_defs) { }
    
    MyClass::~MyClass() {
      // Inhalt von "finalize" stattdessen hier
    }
    

    willst, um

    MyClass obj(pseudo_jets, jet_defs);
    

    schreiben zu können? Manuelle Aufräumarbeiten sind dann nicht mehr notwendig, weil

    {
      MyClass obj(foo, bar);
    
      ...
    } // MyClass::~MyClass() hier ausgeführt und der von obj belegte Speicher freigegeben wird.
    


  • HeXor schrieb:

    Fehlermeldung

    FastjetTool.cpp:81: error: no match for ‘operator=’ in ‘((FastjetTool*)this)->FastjetTool::_cluster = fastjet::ClusterSequence(((const std::vector<fastjet::PseudoJet, std::allocator<fastjet::PseudoJet> >&)
    ((const std::vector<fastjet::PseudoJet, std::allocator<fastjet::PseudoJet> >*)(&((FastjetTool*)this)->FastjetTool::_pseudoJets))), 
    ((const fastjet::JetDefinition&)((const fastjet::JetDefinition*)(&((FastjetTool*)this)->FastjetTool::_jetDef))), 
    ((const bool&)((const bool*)(& false))))’
    include/fastjet/ClusterSequence.hh:66: note: candidates are: fastjet::ClusterSequence& fastjet::ClusterSequence::operator=(fastjet::ClusterSequence&)
    

    Der Compiler sagt dir, dass dein Kopier-Konstruktor die falsche Signatur hat. Du musst den Parameter als const kennzeichnen. Die übliche Signatur sieht daher so aus.

    T& operator = (T const&)
    

    Damit gibts du dem Aufrufer die Garantie, dass du das Objekt nicht veränderst. In Kombination mit const-Memberfunktionen, die du vermutlich noch nicht kennst, ist das sehr sinnvoll.

    HeXor schrieb:

    Ja das hatte ich auch eben gesehen, entschuldigung (und trotzdem danke für die nette reaktion...). Vielleicht ist es so besser:

    Eine MyClass.hpp file:

    Class MyClass {
      public: 
       //ein Objekt
       MyObject obj;
       //ein Pointer
       MyObject *objPointer;
       //eine Funktion
       void foo();
       void finalize();
    };
    

    Eine MyClass.cpp file:

    void MyClass::foo() {
      MyObject tmp(paramt1, param2);
      obj = tmp;
    
      objPointer = new MyObject(param1, param2);
    
      [...verarbeitung...]
    
    }
    
    void MyClass::finalize() {
      delete objPointer;
    }
    

    C++ hat, im Gegensatz zu Java (C++ <3) Destruktoren, die bei Zerstörung automatisch aufgerufen werden. Mit der Suchmaschine deiner Wahl (Als ob jemand was anderes als Google verwenden würde) findest du dazu bestimmt was.

    Abgesehen davon ist der Zeiger immer noch nicht notwendig.

    HeXor schrieb:

    Die main

    //ohne params und bla, einfach nur main funktion halt
    main() {
      MyClass bar;
      bar.foo();
      bar.finalize();
    }
    

    main muss in C++ int zurückgeben. Allerdings ist es in der main erlaubt, kein return hinzuschreiben, in diesem Fall wird 0 zurückgegeben.

    HeXor schrieb:

    Der Pointer soll eben dann noch in vielen anderen Funktionen benutzt werden können.

    Mit diesem Satz fange ich nichts an.

    HeXor schrieb:

    Und eigentlich müsste ich ja dann korrekter weise (auch wenn dann in diesem Beispiel das Ende der Programms erreicht ist) den Pointer am Ende mit finalize() aufräumen.

    Nimm die oben von mir angesprochenen Destruktoren, dann musst du gar nichts machen.

    P.S.: Der "fehlende" GC von C++ fehlt überhaupt nicht. Es ist so gewollt, dass C++ keinen hat. Mag sein, dass das für dich als Javaner erstmal total veraltet rüberkommt, allerdings hat C++ mit RAII einen sehr guten, meiner Meinung nach allen anderen Sprachen überlegenen Mechanismus fürs Resourcen-Management. In Java fällt sowas schnell mal unter den Tisch, von den ganzen hässlichen try-catch-finally Blöcken möchte ich gar nicht erst reden.

    Es stimmt auch, dass GCs einige Probleme von manueller Speicherverwaltung (Fragmentierung, Zyklische Referenzen, ...) auf eine für den Programmierer einfache Weise lösen können. Letzteres kann jedoch bereits durch die Verwendung von weak_ptr umgangen werden, und gegen Fragmentierung hilft ein eigenen Allokator mit speziellen Smartpointern, die es erlauben, den Speicher auch mal rumzuschieben. Alles nicht sehr einfach, aber machbar.

    P.P.S.: Ich vermute mal, dass dein Projekt mehrere tausend Zeilen Code hat, die du nun erstmal korrigieren musst. Ich fände es zwar besser, wenn du das tun würdest, allerdings gibt es auch für C++ GCs. Ein Beispiel ist der Hans Boehm GC.



  • @seldon

    Im prinzip ist dein Vorschlag richtig, allerdings kann ich leider nicht beim Definieren des MyClass Objekts direkt die _cluster variable mittels Übergabe der beiden Parameter definieren, weil die beiden Parameter ebenfalls interne Parameter der Klasse sind, welche erst noch (durch zwei Funktionen mit komplexerem Inhalt) definiert werden müssen.

    Deshalb muss ich an einem Punkt in der Klasse diese Variable definieren. Um mich von Pointern zu entfernen wollte ich dieses in der *.hpp als Klassen Member Variable deklarierte Objekt _cluster in einer der Funktionen in der *.cpp also mittels

    _cluster = fastjet::ClusterSequence(param1,param2);
    

    definieren, was aber mit der obigen Fehlermeldung fehlgeschlagen ist. Die Implementierung hinter diesem Objekt ist ein externes Tool welches ich einbinde, und zweckes updates leider nicht verändern kann/sollte. Wenn also wie es scheint in diesem Tool der "=" Operator überladen wurde, bleibt mir nichts anderes übrig als den Weg über eine temporäre Variable zu wählen

    fastjet::ClusterSequence tmp(param1,param2);
    _cluster = tmp
    

    Oder seht ihr einen anderen Weg?



  • 314159265358979 schrieb:

    Die übliche Signatur sieht daher so aus.

    T& operator = (T const&)
    

    Damit gibts du dem Aufrufer die Garantie, dass du das Objekt nicht veränderst. In Kombination mit const-Memberfunktionen, die du vermutlich noch nicht kennst, ist das sehr sinnvoll.

    Das ist gerade nicht der Grund, siehe Seldons Post eins vor deinem. BTW. kann man const-Memberfunktionen auch problemlos bei non-const-Objekten verwenden. Andersrum (non-const-Methoden auf const-Objekte) gehts halt nicht.



  • 314159265358979 schrieb:

    HeXor schrieb:

    Der Pointer soll eben dann noch in vielen anderen Funktionen benutzt werden können.

    Mit diesem Satz fange ich nichts an.

    ^^ Du hast aber schon was damit angefangen - darauf geantwortet 😛



  • Es gibt einfach zu wenig brauchbare Informationen. Sorry, aber so kann man dir leider nicht helfen.

    Von dem was ich bislang aber erahnen kann vermute ich, dass dein jetziges Problem eine unselige Aneinanderreihung von vielen anderen Dingen ist, die man in C++ eben anders als in Java löst. Ich glaube nicht, dass sich da noch viel retten lässt.



  • otze schrieb:

    Von dem was ich bislang aber erahnen kann vermute ich, dass dein jetziges Problem eine unselige Aneinanderreihung von vielen anderen Dingen ist, die man in C++ eben anders als in Java löst. Ich glaube nicht, dass sich da noch viel retten lässt.

    Das ist, glaube ich, die wichtigste Aussage, die bisher in diesem Thread gefallen ist. Dem kann ich mich nur anschließen.



  • 314159265358979 schrieb:

    otze schrieb:

    Von dem was ich bislang aber erahnen kann vermute ich, dass dein jetziges Problem eine unselige Aneinanderreihung von vielen anderen Dingen ist, die man in C++ eben anders als in Java löst. Ich glaube nicht, dass sich da noch viel retten lässt.

    Das ist, glaube ich, die wichtigste Aussage, die bisher in diesem Thread gefallen ist. Dem kann ich mich nur anschließen.

    Wer mir nicht helfen will muss es ja auch nicht tun, aber dann auch nicht solche Kommentare ablassen...

    Ich kann euch gerne meine ca. 25 files mit ca. 200-2000 Zeilen Code pro file schicken, wenn ihr dann genug Informationen habt.

    Ich denke ich habe es mittlerweile mehr als deutlich gemacht.

    Eine Klasse MyClass mit eine Member Variable _cluster, welche ich in einer Funktion foo() der Klasse MyClass initialisieren muss, damit sie auch in anderen Funktionen bla(), muh(), bar() der Klasse MyClass zur Verfügung steht. Eine definition beim definieren des MyClass objekts ist aus den beschriebenen Gründen nicht möglich, da erst innerhalb der MyClass Klasse einige Variablen dafür berechnet/definiert werden müssen. Um pointer zu vermeiden soll eine direkt Definition her, welche hier aber nicht mit _cluster = ??? realisierbar ist, da das zu definierende Objekt von einem importierten Tool deklariert wird, welches ich nicht verändern kann und welches offensichtlich den "=" Operator überlädt, verwendet werden. Daher brauche ich einen anderen Weg um dieses (ja möglichst ohne Pointer) zu realisieren, welche ich durch dem temporären Weg (der übrigens funktioniert, aber nicht schön aussieht) realisiert habe.

    Ich danke allen die mir versuchen zu helfen, aber kommentare wie "dir ist nicht zu helfen" helfen eben nicht. Und scheinbar sehen andere hier keinen hoffnungslosen Fall sondern äußern gute Vorschläge. Es ist schade wenn man in einem neuen Board eine Hoffnung sieht und sich anmeldet und dann im ersten Thread solche Kommentare bekommnt, obwohl man VERSUCHT ein Minimalbeispiel zu basteln und Informatioen zu geben ohne 20.000 Zeilen code zu posten, wie es viele ander Anfänger selbstverständlich tun. Danke.


  • Mod

    HeXor schrieb:

    Ich danke allen die mir versuchen zu helfen, aber kommentare wie "dir ist nicht zu helfen" helfen eben nicht. Und scheinbar sehen andere hier keinen hoffnungslosen Fall sondern äußern gute Vorschläge. Es ist schade wenn man in einem neuen Board eine Hoffnung sieht und sich anmeldet und dann im ersten Thread solche Kommentare bekommnt, obwohl man VERSUCHT ein Minimalbeispiel zu basteln und Informatioen zu geben ohne 20.000 Zeilen code zu posten, wie es viele ander Anfänger selbstverständlich tun. Danke.

    Das ist kein Bashen auf den Anfänger, sondern die nüchterne Feststellung, dass dir bei der Art wie du die Fragen stellst, keine nützliche Antwort zu geben ist, außer so Allgemeinfloskeln wie "C++ ist nicht Java" oder "Das ist Scheiße, wie du das jetzt machst". Nützen dir diese Aussagen etwas? Wenn nicht, dann musst du beantwortbare Fragen stellen. Das ist keine böse Absicht, dass dir niemand gute Antworten gibt, es liegt an dir. Und viel schlimmer ist, dass du das nicht einsiehst und dich gleich persönlich angegriffen fühlst, wenn man dich nach drei Seiten nutzloser Spekulation vermehrt auf diesen Umstand hinweist.



  • HeXor schrieb:

    da das zu definierende Objekt von einem importierten Tool deklariert wird, welches ich nicht verändern kann und welches offensichtlich den "=" Operator überlädt, verwendet werden.

    Der operator= wird nicht von einem Objekt überladen - das wird in einer Klasse erledigt.
    Und wenn du diese Klasse nicht verändern kannst (da "externes Tool", wie du sagst) ist dir leider auch nicht zu helfen. Entweder du schaffst es, dass das Problem im nächsten Release des Tools beseitigt wird, oder du lebst mit dem Workaround mit dem temporären Objekt.



  • Ich hab mal ein bisschen nachgeforscht. Handelt es sich um diese Bibliothek?

    Ich kann darin zumindest in der neuesten Version keine solche Überladung finden. Ich vermute, dass einer der Member von ClusterSequence keinen assignment-Operator hat, der ein konstantes Quellobjekt annimmt (im Zweifel fastjet::SharedPtr); dann kann der Compiler für ClusterSequence keinen operator=(ClusterSequence const &) generieren.

    Ich weiß aus dem Stand allerdings jetzt nicht, ob der Compiler in solchen Fällen einen operator=(ClusterSequence&) generieren sollte. Könnte eine gcc-Erweiterung sein.

    Am besten wäre vom Design her natürlich, wenn du keine halbfertigen FastJetTool-Objekte herumreichen müsstest (dann bestünde auch dieses ganze Problem nicht), aber wenn dir dieser Weg nicht offen steht, wäre ein shared_ptrfastjet::ClusterSequence hier m.E. vertretbar. Lokalität scheint hier eh nicht gewahrt zu sein, also meh in Bezug auf cache-misses. Was du allerdings nicht machen solltest, ist einen nackten Zeiger in das Objekt zu stecken.



  • seldon schrieb:

    Was du allerdings nicht machen solltest, ist einen nackten Zeiger in das Objekt zu stecken.

    Also ist meine temporäre Variante nicht vertretbar mit:

    fastjet::ClusterSequence tmp(param1,param2);
    _cluster = tmp;
    


  • So, jetzt hab ich das nochmal im Standard nachgeschlagen. Also, der gcc verhält sich da korrekt; wenn ein X &X::operator=(X const &) nicht generiert werden kann, wird (sofern möglich) ein X &X::operator=(X&) generiert. Das wird hier passiert sein.

    Vom C++-Standard her ist die temporäre Variante also möglich. Ob sie hier funktioniert, hängt davon ab, ob die Entwickler der ClusterSequence-Klasse sich Gedanken um Kopiersemantik gemacht haben. Die Verwendung eines SharedPtr deutet ein bisschen darauf hin (ohne Kopien wäre der shared-Teil überflüssig), aber ich werde mich hüten, kategorische Aussagen über Bibliotheken zu machen, mit denen ich mich überhaupt nicht auskenne. Werden in der Dokumentation der Bibliothek manchmal ClusterSequence-Objekte kopiert? Falls ja, ist deine Variante unbedenklich und im Zweifel auch besser, als eine zusätzliche Indirektion einzuführen.



  • Was mir gerade gekommen ist, ist die Idee das ganze mit dem Destruktor der Klasse zu lösen.

    Also:

    Header file *.hpp

    class MyClass {
    
    public:
      //Konstruktor und Destruktor
      MyClass();
      ~MyClass();
    
      //Funktionen
      void foo();
      void bar();
    
      //Member variable
      fastjet::ClusterSequence *_cluster;
    }
    

    Code file *.cpp

    MyClass() {}
    
      ~MyClass() {
         delete _cluster;
      }
    
      void MyClass::foo() {
        _cluster = new ClusterSequence(param1, param2);
      }
    
      void MyClass::bar() {
        [..processing..]
      }
    

    Main function

    int main(int argc, char *argv[]) {
      MyClass obj;
      obj.foo();
      obj.bar();
     return 1;
    }
    

    In diesem Fall also doch wieder einen Pointer verwenden, diesen aber aufzuräumen sobald das Klassen Object zerstört wird, also diesen im Klassen Destruktor löschen.
    Zwar bedeutet das wieder manuelle GarbageCollection, stellt aber doch sicherlich eine in sich konsistente Methode dar, welche zusätzlich die unschöne temporäre Methode umgeht!?



  • HeXor schrieb:

    Main function

    int main(int argc, char *argv[]) {
      MyClass obj;
      obj.foo();
      obj.bar();
     return 1;
    }
    

    Mach mal:

    int main(int argc, char *argv[]) {
      MyClass obj;
      MyClass obj2(obj);
    }
    

    Tipp: Du solltest den Kopier- und Zuweisungsoperator implementieren oder unschädlich machen 😉 .


Anmelden zum Antworten