Memory Leaks - mit VS.net?



  • hab am Ende eines Testrahmens "_CrtDumpMemoryLeaks()" (<crtdbg.h> inkludiert) und es hagelt Memleaks. Wie krieg ich mehr Informationen von dem Debugger? War das _Crtdump... nicht extra für C gedacht? Dachte es gibt im VS.net extra eine überwachung - denn ohne diese Dumpfunktion beendet das Programm ohne Fehler - auch bei maximalen Warning level?!
    Was ist PC Lint genau? Kann man das nicht auch dafür gebrauchen?



  • Also konnte das Problem lokalisieren:
    In einer Klasse gibt es ein Array von Charpointers (-> c-string) (z.B. char* carray[50]). was muss genau im Destruktor stehen um den Speicher wieder vollständig freizugeben?



  • "char*" kann ungefähr alles sein. Hängt davon ab, womit der Speicher allokiert wurde. new? new[]? malloc? <insert 100 andere Möglichkeiten here>

    Am besten löst man solche Probleme, indem man die entsprechende Wrapperklasse verwendet: boost::scoped_ptr<> für new, boost::scoped_array für new[] etc... (www.boost.org). Oder wenn du mit den char*s einfach nur Strings darstellen willst, std::string (siehe Lieblingsdoku). Dann ist der Typ nicht nur aussagekräftiger, dir bleibt auch noch das Schreiben eines Destruktors erspart.



  • Danke für die Antwort - bin leider mit c++ erst beim Anfang: hab zwar schonmal was von wrapperklassen gehört (war das nicht ne schnittstellenklasse?) aber keine ahnung davon 😞
    gibts denn keine Möglichkeit das Problem mit c-strings zu lösen und ohne verwendung von std::string?
    Hab hier mal ein Beispiel (das nicht funktioniert - d.h. der Destruktor stürzt ab)

    class TestKlasse
    {
    public:
    	TestKlasse(char *);
    	~TestKlasse();
    	char** array;
    };
    
    TestKlasse::TestKlasse(char * string1)
    {
    	array = new char* [10];
    	for (int i = 0; i < 10; i++)
    	{
    		array[i] = new char[strlen(string1)];
    		strcpy(array[i], string1);
    	}
    }
    
    TestKlasse::~TestKlasse()
    {
    	for (int i = 0; i < 10; i++) 
            delete [] array [i] ; 
        delete [] array ; 
    }
    

    Das Ding macht nichts anderes, als 10x den übergegebenen String in dem Array zu speichern.
    1. Wieso ist da der Fehler?
    2. Wie gehts richtig?
    3. Und was ist generell besser fürs Abspeichern von ein paar Strings?



  • hat denn keiner eine Antwort warum der dtor nicht geht?? bin grad am kopfzerbrechen und würd gern mit ruhigem gewissen ins bett gehen!



  • 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.


Log in to reply