Memory Leaks - mit VS.net?



  • Ich verstehe nicht ganz, wieso array ein char** ist.

    Versuchs doch mal mit char *array und array = new char[10].
    Dann löscht du im Destruktor das ganze mit delete[] array.

    Funktioniert wunderbar bei mir.



  • meinst du das hier:

    class TestKlasse
    {
    public:
    	TestKlasse(char *);
    	~TestKlasse();
    	char* array;
    };
    
    TestKlasse::TestKlasse(char * string1)
    {
    	array = new char [strlen(string1)];
    	strcpy(array, string1);
    
    }
    
    TestKlasse::~TestKlasse()
    {
    	delete[] array; 
    }
    

    Dann kann ich aber nur eine Zeichenkette speichern - möchte aber gleich mehrere sichern, z.B. 10.
    Komischerweise kackt er selbst hier ab 😡 glaube mein Vstudio hat ne macke! was ist denn jetzt an dem Code schon wieder falsch?



  • Wenn du zehn Zeichenketten abspeichern willst, dann erstell halt einfach 10 Instanzen deiner Klasse. Ist doch viel einfacher.



  • die Klasse hat auch kein Sinn. Es geht um ein fertiges Codestück - ich würde es selber lieber in einen container schmeissen.
    Ziel ist es jedenfalls mehrere Zeichenkette in einer Instanz zu verwalten - wenns geht c-like mit array von char*.



  • Na dann, wenn sie keinen Sinn hat... 🙄

    Ich dachte, du brauchst eine String-Klasse.



  • Gumble schrieb:

    array[i] = new char[strlen(string1)];
    

    Der angeforderte Buffer ist ein Zeichen zu klein.



  • danke -king-, das war der (eine Fehler). Leider hab ich noch grundsätzliche Verständnisprobleme. und zwar wird der Destruktor nicht fürs pTestobjekt aufgerufen. schlimm das es ein Pointer ist?

    #include <crtdbg.h>
    class TestKlasse
    {
    public:
    	TestKlasse(char *);
    	~TestKlasse();
    	char* array;
    };
    
    TestKlasse::TestKlasse(char * string1)
    {
    	array = new char [strlen(string1)+1];
    	strcpy(array, string1);
    
    }
    
    TestKlasse::~TestKlasse()
    {
    	delete[] array; 
    }
    
    int main (void)
    {
    	{
    		TestKlasse* pTestobjekt = new TestKlasse("gehtnicht");	
    		TestKlasse Testobjekt("geht");
    	}
    
    	_CrtDumpMemoryLeaks();
    	return 0;	
    }
    


  • es fehlt ja auch noch ein

    delete pTestobjekt;
    

    🤡



  • Gumble schrieb:

    Ziel ist es jedenfalls mehrere Zeichenkette in einer Instanz zu verwalten - wenns geht c-like mit array von char*.

    [don quijote reitet wieder]Warum denn char* wenns doch std::string aus <string> gibt?[/don quijote reitet wieder]

    std::string meineStrings[10]; // ist das zu elegant und einfach für Dich? :p
    


  • Mit std::strings hättest du dann auch nicht das Problem, dass das Kopieren und Zuweisen von Instanzen deiner Testklasse zu einem Absturz führen wird. Was spricht denn nun gegen sie?



  • 🤡 schrieb:

    es fehlt ja auch noch ein

    delete pTestobjekt;
    

    🤡

    aah, wusste nicht das ich den dtor expliziet aufrufen muss - bei normalen Instanzen (keine Pointer) wird er am Ende des Gültigkeitsbereich ja von alleine aufgerufen. Danke!

    nman, operator void
    jo, hier habt ja recht 🤡 Werd zusehen dass durchgängig c++-strings verwendet werden. Kostet das eigentlich viel Geschwindigkeit? Das dumme ist nur, dass später (grafik)funktionen aufgerufen werden, die nur char* akzeptieren - aber dann muss halt alles nochmal mit c_str() umgewandelt werden.
    Den Fehler von dem ersten Codestück weiss ich allerdings immer noch nicht - warum geht das delete [] array [i] ; nicht??



  • Gumble schrieb:

    Kostet das eigentlich viel Geschwindigkeit? Das dumme ist nur, dass später (grafik)funktionen aufgerufen werden, die nur char* akzeptieren - aber dann muss halt alles nochmal mit c_str() umgewandelt werden.

    Die Implementierungen, die ich kenne, wandeln in c_str() nichts um, sondern geben einfach einen Zeiger zurück, das kostet also wirklich gar nichts 🙂 Die Kosten von std::string gegen char* sind vor allem beim Kopieren höher, also solltest du die Strings in der Regel als "const string&" übergeben - aber die Regel gilt eh für alle größeren Objekte.
    (Und selbst wenn du *gemessen* hast, dass std::string das Programm verlangsamt, dann schreib dir lieber eine eigene spezielle String-Klasse, die dir das delete abnimmt. delete hat IMHO außerhalb von solchen Helferklassen nichts zu suchen, weil man es eben doch mal vergessen, verdoppeln oder sonstwas damit machen kann.)



  • danke, die strings sind schon ne feine Sache. Interessieren tuts mich aber trotzdem (gehört eigentlich ins C-Forum) wie ich mit charpointer hantiere. z.B. gibts eine Möglichkeit das eine Funktion eine Zeichenkette zurückliefert, ohne hier beim Aufruf einen Speicherbereich übermittelt zu haben?

    char * foo( void )
    {
       char* ptr_chartemp = new char[4];
       ctemp = "bar";
       return ptr_chartemp;
    }
    

    Hier wird doch der Pointer ptr_chartemp, gleich nach Beenden der Funktion gelöscht, der Speicherbereich bleibt aber erhalten (Mem.Leak) und es besteht auch keine Chance mehr ihn zu freizugeben ?! Referenziert ist er ja noch (durch den Rückgabewert)...



  • Ich finde das aber nicht besonders elegant. Wenn eine Funktion einen String zurückgeben soll, dann soll sie halt nen Pointer übernehmen und den verwenden um den String in den Speicher zu schreiben.
    Ich würde nicht innerhalb einer Funktion Speicher anfordern und dann außerhalb ihn wieder freigeben (oder auch nicht!).



  • Gumble schrieb:

    char * foo( void )
    {
       char* ptr_chartemp = new char[4];
       ctemp = "bar";
       return ptr_chartemp;
    }
    

    Das geht nicht, weil du in der zweiten Zeile (ctemp soll wohl auch ptr_chartemp sein?) den Zeiger vom allokierten Speicher auf ein Stringliteral umbiegst. Schon danach kannst du den Speicher nicht mehr freigeben. Wenn du "bar" mit strcpy in *ptr_chartemp kopieren würdest, könnte der Aufrufer der Funktion den Speicher über delete[] freigeben und alles wäre gut. Allerdings wird der Code dann schnell sehr zerbrechlich 🙂
    Wenn du eine Funktion allokierten Speicher zurückgeben lassen willst, geht das normalerweise am besten mit std::auto_ptr, der genau für sowas gebaut wurde. Allerdings kann man diesen hier nicht verwenden, weil der Speicher mit delete[] und nicht mit delete freigegeben werden muss.



  • operator void schrieb:

    Das geht nicht, weil du in der zweiten Zeile (ctemp soll wohl auch ptr_chartemp sein?) den Zeiger vom allokierten Speicher auf ein Stringliteral umbiegst. Schon danach kannst du den Speicher nicht mehr freigeben. Wenn du "bar" mit strcpy in *ptr_chartemp kopieren würdest, könnte der Aufrufer der Funktion den Speicher über delete[] freigeben und alles wäre gut. Allerdings wird der Code dann schnell sehr zerbrechlich 🙂
    Wenn du eine Funktion allokierten Speicher zurückgeben lassen willst, geht das normalerweise am besten mit std::auto_ptr, der genau für sowas gebaut wurde. Allerdings kann man diesen hier nicht verwenden, weil der Speicher mit delete[] und nicht mit delete freigegeben werden muss.

    jo, sollte ptr_chartemp heissen. Haben jetzt doch mehr std::strings eingebaut und die Leaks sind weg 🙂 std::auto_ptr muss ich mir nochmal anschauen. Will aber versuchen weg von den Pointern und mehr mit Objekte und Referenzen auf diese arbeiten. Was nur seltsam an der Fkt _CrtDumpMemoryLeak() ist, dass sie auch noch gültigen (referenzierten) Speicher dumped:

    // gehört zum Code weiter unten
    
        { 
            TestKlasse* pTestobjekt = new TestKlasse("foo");     
            _CrtDumpMemoryLeaks(); // liefert den Leak
    
        } 
    
        _CrtDumpMemoryLeaks(); // alles ok, da der dtor aufgeräumt hat
    

    Er zeigt also allen dynamischen Speicher an - gibts vielleicht irgendeine Debuggoption oder (_Crt-)Funktion, mit der ich an jeder Stelle des Codes gucken kann, ob noch alles klar mit meinem Speicher ist (-> unreferenzierten Bereich)? So kann ich die _CrtDumpMemoryLeaks() nur am Ende und außerhalb des Gültigkeitsbereiches verwenden...

    ps: was hat es eigentlich mit dem foo & bar immer auf sich? 😕
    Gibts da einen Hintergrund?



  • Optimizer schrieb:

    Ich würde nicht innerhalb einer Funktion Speicher anfordern und dann außerhalb ihn wieder freigeben

    Stimmt, sollte man vermeiden ausser es ist wirklich so gewollt (also bei speziellen Alloc-Funktionen etc.).


Anmelden zum Antworten