Destruktor-Aufruf scheitert



  • Genau, zeig mal, was Smoothing macht.

    Das Interessante ist, was mit dem Zeiger gemacht wird, der später zurückgegeben wird.

    So als Idee:
    Kommentier mal das new im Konstruktor aus. Ist wirklich nur so eine Idee...



  • schließe mich estardu_de an.

    was macht m_pTempDataSet = Smoothing(m_pLeftFile, 9); ?
    zuerst allozierst du für m_pTempDataSet ein objekt auf dem heap, und irgendwann später scheinst du dem zeiger etwas anderes zuzuweisen, nämlich den rückgabewert von Smoothing.
    frag ich mich: was passiert mit dem ersten objekt, dass du dadurch vielleicht verlierst? wo wird das deletet?
    und ich frage mich, ob das, was da bei Smoothing "hergestellt" wurde, innerhalt der methode ein objekt war, aber nach der methode vielleicht nicht mehr existiert... oder garkein objekt war..



  • Ups, das sind plötzlich viele Antworten/Fragen... 🙂

    OK, ich erstatte Bericht:

    Smoothing ist ein Tiefpass, der eine Methode der Klasse darstellt. Er bekommt einen Pointer auf einen Datensatz und liefert auch einen Pointer zurück. Intern arbeitet die Funktion mit einem temporären Datensatz:

    Header:

    CDataSet *Smoothing(CDataSet*, size_t);
    

    .cpp:

    CDataSet* CLineAnalyzerDlg::Smoothing(CDataSet* dsVec, size_t iLOS)
    {
        // iLOS = Level of smoothing
        // Anzahl Messwerte, über die gemittelt wird
        std::vector<CDataRow> TempVec = dsVec->GetDataVector();
        std::vector<CDataRow> SmoothedVec;
        ...
        // Rechnen rechnen rechnen
        ...
        dsVec->SetDataVector(SmoothedVec);
        return dsVec;
    }
    

    Also ich übergebe mit dem Aufruf von Smothing den Zeiger auf den Datensatz. Smoothing() arbeitet damit und gibt ihn per return zurück. Gut? Schlecht? Entsteht hier irgendwo eine Kopie, die ich nicht sehe und/oder lösche?



  • ich seh nur das:
    m_pTempDataSet = Smoothing(m_pLeftFile, 9);

    du übergibst einen zeiger m_pLeftFile, wahrscheinlich vom datentyp CDataSet*, und die funktion gibt einen zurück, den du dann zuweist an m_pTempDataSet.
    was passiert mit dem zuerst erstellten objekt von m_pTempDataSet, wenn du zwischendrin neu zuweist? und: worauf zeigt der m_pTempDataSet dann nach zuweisung eigentlich genau? deletest du dieses nächste objekt irgendwo?



  • Also m_pTempDataSet wird im Konstruktor erzeugt, dann das erste Mal bei der Smoothing()-Funktion benutzt. Zwischendrin passiert mit m_pTempDataSet garnichts (siehe 1. Beitrag).

    du übergibst einen zeiger m_pLeftFile, wahrscheinlich vom datentyp CDataSet*, und die funktion gibt einen zurück, den du dann zuweist an m_pTempDataSet.

    Korrekt.

    was passiert mit dem zuerst erstellten objekt von m_pTempDataSet, wenn du zwischendrin neu zuweist?

    Keine Ahnung, schätzungweise ist das der Grund, warum ich das Speicherloch habe? Also habe ich was grundlegendes falsch verstanden. Wenn ich einen Zeiger im Konstruktor mit "zeiger = new objekt" erzeuge habe ich ein Objekt und ein Zeiger auf dieses Objekt. Sprich wenn ich den Zeiger das erste mal zuweise, ist das Objekt verloren und idlet im Speicher rum!? Ist das richtig? 😕

    Wenn ja, muss ich den Aufruf im Konstruktor einfach nur weglassen, oder? Dann gehts. Dann hätte ich nur einen typisierten Zeiger der erstmal uninitialisiert ist, bei Smoothing() dann aber einen Wert bekommt.



  • Du hast das glaube ich richtig erkannt. 🙂

    Initialisier den Zeiger aber bitte mit NULL und nicht überhauptnicht. ⚠

    Ein Zeiger ist nur eine Adresse. Wie ein Zettel, wo du draufschreibst, wo dein Auto parkt.

    Du nimmst ihn und legst ihn auf den Tisch (CAuto pZettel;)*
    Nun weiß du nicht, was draufsteht. Es könnte ja noch eine Notiz von irgendwann mal drauf sein. Oder auch nix.

    Also löscht man ihn (pZettel = NULL;)
    Z.B. alles wegradieren, wenn man mit Bleistift geschrieben hat.
    Wenn du nun draufguckst, weißt du, dass du kein Auto hast. Weil ja kein Parkplatz auf dem Zettel steht.

    Also kaufst du dir ein neues Auto, das steht beim Händler. (pZettel = new CAuto;)
    Nun steht auf dem Zettel z.B. "Autohaus Voets, links neben dem Eingang".

    Soweit, so gut - hoffe ich.

    Jetzt kommt dein Freund vorbei, findet den Zettel und überschreibt ihn mit dem Parkplatz seines Autos. "Dritter Parkplatz von links, gegenüber vom Haus" (pZettel = pAutoVomFreund;)
    Jetzt hast du keine Ahnung mehr, wo DEIN Auto steht und es ist verloren und wird auf immer und ewig auf dem Parkplatz stehen und vor sich hin rosten. 😃

    Schließlich hast du die Schnauze voll und verschrottest das Auto, auf das der Zettel verweist. (delete pZettel;)
    Nun hat dein Freund kein Auto mehr, der Parkplatz ist leer. Aber das Auto, was du gekauft hast steht immer noch beim Händler und rottet vor sich hin. Aber eigentlich weißt du von dem ja gar nix mehr - auf dem Zettel ist ja der leere Parkplatz vermerkt.
    Hier merkst du auch, warum es einen Absturz gibt, wenn kein Objekt hinter dem Zeiger ist. Versuch mal, mit dem Parkplatz loszufahren...

    Also musst da noch kennzeichnen, dass du kein Auto mehr hast. (pZettel = NULL;)
    Jetzt ist der Zettel wieder leer und das Auto... 🙄

    Naja, ich hatte grade kreative Langeweile. 😃
    Fühl dich nicht verärmelt, so oder ähnlich hat es bisher noch jeder verstanden. 🙂



  • Hey nein, ich finde die Beschreibung total klasse, das sollte man konservieren, ich hatte immer Probleme mit Objekt-/Zeiger-auf-Objekt-Erstellung, da ich das immer nicht auseinanderhalten konnte. Jetzt wird mir einiges klar.

    Also:

    Zeiger definieren:

    private:
        CDataSet *m_pTempDataSet;
    

    Zeiger erstellen und mit NULL initialisieren:

    CLineAnalyzerDlg::CLineAnalyzerDlg(CWnd* pParent /*=NULL*/)
        : CDialog(CLineAnalyzerDlg::IDD, pParent)
        , m_pTempDataSet(0)
    {
        m_pTempDataSet = NULL;
    }
    

    Zeiger zuweisen...:

    m_pTempDataSet = Smoothing(m_pLeftFile, 9);
    

    ...und "irgendwann" entsorgen:

    CLineAnalyzerDlg::~CLineAnalyzerDlg()
    {
        delete m_pTempDataSet;
    }
    

    😃 Ich glaube, ich blicke durch. THX. 👍 👍 👍



  • Bitteschön. 🙂

    Kleine Korrektur:

    zwette schrieb:

    Zeiger definieren und erstellen:

    private:
        CDataSet *m_pTempDataSet;
    

    Zeiger mit NULL initialisieren:

    CLineAnalyzerDlg::CLineAnalyzerDlg(CWnd* pParent /*=NULL*/)
        : CDialog(CLineAnalyzerDlg::IDD, pParent)
        , m_pTempDataSet(0)
    {
        m_pTempDataSet = NULL;
    }
    

    Und doppelt hält besser?
    Guck mal genau hin:

    , m_pTempDataSet(0)
    {
        m_pTempDataSet = NULL;
    


  • Hallo,

    ich habe ein ähnliches Problem:

    std::vector<Node> nodes;
    Node* newNode;
    while(xml && xml->read()) {
    switch(xml->getNodeType()) {
    case EXN_ELEMENT_END: {
    if(!strncmp("link", xml->getNodeName(),7)) {
    nodes.push_back(*newNode);
    if(nodeNr > 0)
    nodes.at(nodeNr-1)->child = nodes.at(nodeNr);
    }
    }

    case EXN_ELEMENT: {
    if (!strncmp("link", xml->getNodeName(),5) ) {
    if(junctionNr == 6)
    return -2; //zu viele Gelenke

    //neuen Knoten dem Knotenvektor hinzufügen
    newNode = 0;
    newNode = new Node();

    //Aktueller Knoten ist Kindknoten von vorigem Knoten (falls vorhanden)
    ++nodeNr;

    newNode->name = "hallo";

    }
    }
    }
    }

    Hierbei ist Node eine Klasse, die viele Attribute wie Name usw. enthält, während nodes ein vector von Node-Objekten (nicht Pointern) in einer anderen Klasse, die included wird, ist. Die Daten werden hierbei aus einer XML-Datei eingelesen, bei <link> wird der untere case-Teil aufgerufen, bei einem schließenden Tag wird der obere case-Teil aufgerufen. In diesem (vereinfachten und verkürzten) Beispiel soll eine Node den Namen hallo kriegen und dann in den nodesvektor gespeichert werden. Dann soll jeweils der child-Zeiger des Vorgängers auf den aktuellen Knoten zeigen (nodeNr wird auhc gescheit initialisiert, da das aber alles etwas verteilt ist, hab ichs weggelassen).

    Das Problem ist, dass zwar der child - Zeiger umgesetzt wird, aber sobald ich ein neues Objekt (und damit einen Pointer) erstelle, erhalte ich später eine Zugriffsverletzung, weil der child - Zeiger irgendwo ins Nirvana zeigt.

    Wie kann ich denn nun mehrere Objekte erzeugen und in dem Vektor einfügen? Ich habe auch schon versucht, nur ein Node-Objekt (und keinen Pointer) zu erzeugen und in den Vektor einzufügen.

    Wie ich gerade noch bemerkt habe, scheint die push_back - Methode der Vektor - Klasse die destroy - Methode der Nodes aufzurufen, anscheinend, weil der Vektor vergrößert werden muss. Dadurch sind dann die child-Zeiger alle falsch...

    Bitte helft mir, dass ist echt ein riesenproblem für mich!



  • Musst du überhaupt new benutzen in deinem Code?
    vector legt Kopien der Element an, also wenn die klein sind, kannst auch ein richtiges Objekt in den vector stecken anstatt new und delete zu bemühen


Anmelden zum Antworten