dynamische rückgabe



  • Hallo

    Ich habe eine Funktion, die mir die Schnittpunkte von zwei kreisen berechnet. meine Frage ist nur, welchen Datentyp soll ich zurückgeben, bzw wie soll ich die Rückgabe durchführen.

    folgende Situationen sollen in der an der Rückgabe unterscheidbar sein:
    Kreis-A liegt in Kreis-B
    Kreis-B liegt in Kreis-A
    Kreis A und B haben keine Schnittpunkte
    Kreis A und B haben genau einen Schnittpunkt
    Kreis A und B haben genau zwei Schnittpunkte
    (wenn es Schnittpunkte gibt müssen die natürlich auch immer mit angegeben sein)

    ich habe die Klassen Vertex und Circle, die alle wichtigen informationen für mich enthalten. Jede übergabe von Daten mache ich mithilfe von boost::smart_ptr, damit ich mich nicht mehr darum kümmern muss, wo ich welche Daten gespeichert habe.

    ich habe es bisher ein Struct verwendet mit allen Informationen, aber seit ich meine Funktion weiter verschachtelt habe, sind die Destruktoren der Vertices aus einem mir unbekannten Grund Aufgerufen worden, und das Programm ist mit einem Segmentation Fault abgebrochen.



  • Für die Unterscheidung der Situationen bietet sich ein enum an. Da du höchstens zwei Punkte speicherst, scheint mir ein Container zu viel Overhead. Eine Möglichkeit wären zwei Zeiger, die Null sein können:

    // Deine Punktklasse
    struct Point
    {
        float x;
        float y;
    };
    
    // Namensraum als Enum-Workaround, damit Qualifizierung möglich:
    namespace Intersection
    {
        enum Type
        {
            // ...
        };
    }
    
    // Klasse, die dein Schnittpunkt-Resultat hält
    struct IntersectionResult
    {
        Intersection::Type IntersectionType;
        Point*             PointA;
        Point*             PointB;
    };
    

    Hier der Einfachheit halber mal alles ungekapselte struct s. Hast du bereits was Ähnliches versucht? Vielleicht kannst du uns mehr zu deinem Destruktor-Problem sagen...



  • so ähnlich habe ich das auch gelöst, und danke für den hinweiß für den Namespace, aber es lößt nicht mein Problem. Ich hab nochmal versuch das Problem zu minimieren.

    #include <cstdlib>
    #include <iostream>
    #include <boost/shared_ptr.hpp>
    
    using namespace std;
    using namespace boost;
    
    class Object{
    public:
    	int nr;
    	Object(){
    		static int counter = 0;
    		nr = counter++;
    		cout << "Create\t" << nr << endl;
    	}
    	~Object(){
    		cout << "Remove\t" << nr << endl;
    	}
    };
    
    typedef shared_ptr<Object> Pointer;
    
    class Container{
    public:
    	Pointer o1;
    	Pointer o2;
    };
    
    Container foo(){
    	Container con;
    	con.o1 = Pointer(new Object);
    	con.o1 = Pointer(new Object);
    	return con;
    }
    
    Container bar(){
    	Container con1 , con2;
    	con1 = foo();
    	con2.o1 = Pointer(con1.o2);
    	con2.o2 = Pointer(con2.o1);
    	return con2;
    }
    
    int main(int argc, char** argv) {
    	Container con = bar();
    	cout << "ende" << endl;
    }
    
    Create	0
    Create	1
    Remove	0
    Remove	1
    ende
    [Press Enter to close window]
    

    Warum sind die destruktoren vor dem Ende des Programms aufgerufen worden? Die Objecte sollten doch eingentlich noch gespeichert bleiben.



  • Krux schrieb:

    Warum sind die destruktoren vor dem Ende des Programms aufgerufen worden? Die Objecte sollten doch eingentlich noch gespeichert bleiben.

    Nein. Du hast dich vertippt:

    Container foo(){ 
        Container con; 
        con.o1 = Pointer(new Object); 
        con.o1 = Pointer(new Object);  // <--
        return con; 
    }
    

    Und weil du in bar() nur o2 kopierst, der nach wie vor ein Nullzeiger ist, werden die anderen Objekte normal bei Verlassen des Scopes zerstört. Explizite Kopierkonstruktoraufrufe sind übrigens nicht nötig, wenn du shared_ptr s einander zuweist. Das Pointer(..) kannst du also weglassen.

    Container bar(){ 
        Container con1 , con2; 
        con1 = foo(); 
        con2.o1 = Pointer(con1.o2); // con1.o2 ist Null -> con2.o1 auch
        con2.o2 = Pointer(con2.o1); // con2.o2 auch
        return con2; 
    }
    

    Was das Ganze mit deinem ursprünglichen Problem zu tun hat, entzieht sich meiner Kenntnis jedoch vollständig.



  • aua dämlich, danke habs korrigiert.
    ich glaub mein ursprüngliches Programm hat genau solche fehler da was vergessen, hier was falsch gemacht, und am ende nur noch Segmentation fault.

    Jetzt hab ich aber schonmal eine funktionierende version, und ich weiß, dass es funktionieren kann, so wie ich es implementiert habe, ich muss nurnoch die tippfehler suchen.

    Im Projekt ist das Object mein Vertex, Container mein IntersectionResult, foo und bar sind meine beiden verschachtelten Funtionen, um die Schnittpunkte der Kreise zu berechnen.

    Edit:
    ja meine vermutung hat sich bestätigt, ich habe irgendwo ein return vergessen, und darum hat nichts mehr funktioniert.



  • Krux schrieb:

    Im Projekt ist das Object mein Vertex, Container mein IntersectionResult, foo und bar sind meine beiden verschachtelten Funtionen, um die Schnittpunkte der Kreise zu berechnen.

    Okay. Warum sagst du das nicht von Anfang an, sondern verwirrst mit irrelevanten Informationen (z.B. welche Kollisionstypen von Kreisen vorkommen sollen)? Darauf habe ich mich nämlich bei der ersten Antwort konzentriert.

    Ich bin dir nicht böse, aber achte dich das nächste Mal bitte auf eine präzise Fragestellung, so hätte ich mir die Mühe sparen können.

    P.S.:

    Krux schrieb:

    Jede übergabe von Daten mache ich mithilfe von boost::smart_ptr, damit ich mich nicht mehr darum kümmern muss, wo ich welche Daten gespeichert habe.

    Nur der Faulheit wegen solltest du Smart-Pointer nicht benutzen. Bedenke auch, dass sie einen gewissen Overhead durch die Referenzzählung besitzen. Es gibt nicht wahnsinnig viele Anwendungsfälle, in denen wirklich Shared-Ownership-Semantik benötigt wird.

    Wenn du dir bei der Speicherverwaltung nichts überlegen willst, nimm lieber gleich GC-Sprachen. :p



  • Nexus schrieb:

    Krux schrieb:

    Im Projekt ist das Object mein Vertex, Container mein IntersectionResult, foo und bar sind meine beiden verschachtelten Funtionen, um die Schnittpunkte der Kreise zu berechnen.

    Okay. Warum sagst du das nicht von Anfang an, sondern verwirrst mit irrelevanten Informationen (z.B. welche Kollisionstypen von Kreisen vorkommen sollen)? Darauf habe ich mich nämlich bei der ersten Antwort konzentriert.

    Ich bin dir nicht böse, aber achte dich das nächste Mal bitte auf eine präzise Fragestellung, so hätte ich mir die Mühe sparen können.

    Hätte ich gewusst wo das Problem liegt hätte ich mir auch viel Arbeit sparen können, ich wusste es aber nicht, darum habe ich versucht alle Informationen zu geben, die zur Behebung des Problems behilflich sein könnten. letztlich war es ein Syntaxfehler, und keine meiner Informationen war relevant.

    Nexus schrieb:

    P.S.:

    Krux schrieb:

    Jede übergabe von Daten mache ich mithilfe von boost::smart_ptr, damit ich mich nicht mehr darum kümmern muss, wo ich welche Daten gespeichert habe.

    Nur der Faulheit wegen solltest du Smart-Pointer nicht benutzen. Bedenke auch, dass sie einen gewissen Overhead durch die Referenzzählung besitzen. Es gibt nicht wahnsinnig viele Anwendungsfälle, in denen wirklich Shared-Ownership-Semantik benötigt wird.

    Wenn du dir bei der Speicherverwaltung nichts überlegen willst, nimm lieber gleich GC-Sprachen. :p

    Ich verwende C++, weil es dort mittlerweile so viele Brauchbare Bibliotheken gibt, und ich mich da schon gut eingearbeitet habe. Mit java habe ich dieses Projekt sogar angefangen, und ich habe festgestellt, dass ich das ganzo doch lieber auf C++ portieren wollte. Habe dann festgestellt, dass so wie ich es implementiert hatte es ohne GC nicht funktionieren kann, darum hab ich auch den Smart-Pointer eingesetzt.



  • Krux schrieb:

    Ich verwende C++, weil es dort mittlerweile so viele Brauchbare Bibliotheken gibt, und ich mich da schon gut eingearbeitet habe. Mit java habe ich dieses Projekt sogar angefangen, und ich habe festgestellt, dass ich das ganzo doch lieber auf C++ portieren wollte. Habe dann festgestellt, dass so wie ich es implementiert hatte es ohne GC nicht funktionieren kann, darum hab ich auch den Smart-Pointer eingesetzt.

    Ich finde es gut, dass es doch noch Leute gibt, die von Java nach C++ portieren. 🙂

    Du solltest einfach dran denken, dass man hier von Grund auf andere Konzepte verfolgt (z.B. Templates, RAII) und man in C++ ganz anders als in Java programmiert. boost::shared_ptr ist auch kein Ersatz für einen Garbage-Collector, selbst wenn er die Speicherverwaltung erleichtert. Also nicht immer nur Smart-Pointers verwenden - es gibt oft elegantere Wege, die dir noch weniger Arbeit mit dem Speicher aufhalsen. 😉


Log in to reply