Speicherleck nur beim "new"?



  • Hallo, ich habe eine Source Code Analyse meines C++ durchgeführt und bin draufgekommen, dass die Werkzeuge einen Speicherleck nur dann melden, wenn die Referenz mit new erzeugt wird, bevor sie zugewiesen wird. Also zB.:

    char string1[] = "1234567890";
    char* char2 = new char();
    char2 = string1;

    meldet einen Speicherleck (memory leak) falls man später nicht delete char2 ausführt.

    ´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´

    Wenn man aber nur folgendes hinschreibt meldet der Analysator keinen Fehler:

    char string1[] = "1234567890";
    char* char2 = string1;

    heißt es, dass der Speicher ohne "new" nicht reserviert wird und daher das zweite Beispiel kein reserviertes Speicher benutzt und nicht mit delete deallokiert werden muss? (es handelt sich also um keinen Speicherleck?)
    Danke sehr, David



  • Ja das ist richtig. Nur was mit new angefordert wurde muss/darf mit delete freigegeben werden. Daher ist das delete char2 im ersten Beispiel auch ein Fehler (bzw. sogar 2Fehler), da char2 nicht mehr auf den Speicherbereich der durch new angelegt wurde zeigt, sondern auf den Anfang von string1. Du löscht also was du nicht löschen darfst und löscht das was gelöscht werden muss nicht.



  • david.dda schrieb:

    Hallo, ich habe eine Source Code Analyse meines C++ durchgeführt und bin draufgekommen, dass die Werkzeuge einen Speicherleck nur dann melden, wenn die Referenz mit new erzeugt wird, bevor sie zugewiesen wird.

    Welche Referenz?

    david.dda schrieb:

    char string1[] = "1234567890";
    char* char2 = new char();
    char2 = string1;

    meldet einen Speicherleck (memory leak) falls man später nicht delete char2 ausführt.

    Du scheinst new/delete und Zeiger nicht verstanden zu haben. Natürlich sollte hier jedes vernünftige Tool ein Speicherleck melden. char2 ist ein Zeiger, welcher erst auf ein neu im Freispeicher alloziertes char-Objekt zeigt und danach auf das erste Element des string1-Arrays. Wenn Du nach der "char2=string1;"-Zuweisung "delete char2;" schreibst, fliegt Dir Dein Programm um die Ohren, da char2 ja nicht mehr auf das im Freispeicher reservierte char-Objekt zeigt. Du scheinst char* wie std::string benutzen zu wollen. Dann nimm doch auch std::string! 🙂

    david.dda schrieb:

    Wenn man aber nur folgendes hinschreibt meldet der Analysator keinen Fehler:

    char string1[] = "1234567890";
    char* char2 = string1;

    heißt es, dass der Speicher ohne "new" nicht reserviert wird und daher das zweite Beispiel kein reserviertes Speicher benutzt und nicht mit delete deallokiert werden muss? (es handelt sich also um keinen Speicherleck?)
    Danke sehr, David

    Warum sollte der Analysator hier einen Fehler melden? Du forderst hier nichts aus dem Freispeicher an. Das Array string1 lebt im "automatischen" Speicher. Die Lebenszeit des Arrays fängt dann an, wenn die Programmausführung die Stelle der Definition erreicht hat und hört dann wieder auf, wenn die Ausführung den Block verlässt. char2 ist immer noch ein Zeiger. Zeiger können auf alles mögliche zeigen, nicht nur auf dynamisch allozierten Speicher.

    Schau nochmal in Dein C++ Buch rein. Lies Dir die Kapitel über Zeiger und dynamische Speicherverwaltung nochmal durch.

    Gruß,
    SP



  • Hi,

    vorab: Ich bin kein Profi und selbst blutiger Anfänger, daher verlass dich nicht 100%-ig auf meine Ansicht dazu!

    Ich denke es ist so:

    mit "char* char2 = new char();" reserverierst du neuen Speicher (für einen Char bzw String), aber mit "char2 = string1;" 'biegst' du ihn bloß um, denn:

    char2 steht für den Inhalt von dem Speicher namens Char2, sprich die Adresse auf den neu erzeugten Speicher auf dem Heap.
    Blöderweise steht string1 auch nur für eine Adresse (und zwar die des ersten Zeichens vom String). Dies zeigt sich,dadurch dass du auch "*string1" verwenden könntest, dennoch ist ein Arry kein String!

    Somit machst du:
    Der Inhalt von char2 (Adresse!) = Adresse vom ersten Element der Stringliterale.

    Ich bin mir nicht sicher, aber ich glaube das "new char();" ist dann vollkommen verloren.

    char string1[] = "lol";
        char* char2 = string1; 
        cout << char2 << string1 << endl; //lollol
        delete[] char2; // Was soll man auch löschen? Den Speicher des Zeigers nicht und reserviert über diese Adresse wurde ja nichts
        cout << char2 << string1 << endl;//lollol
    

    Ich denke, dass man den Speicher eines Arrys nicht auflösen kann. Den Zeiger kann man hingegen individuell "umbiegen". Also braucht man nur "delete", wenn du auch mit "new" Speicher reserviert hast auf dem Heap.



  • Also im dem Quellcode, den ich analysiert habe (FilleZilla Server) wurde im Change Log ein Eintrag: "fix memory leak" geändert. Ich habe den Memory leak (also delete statement) ausgeklammert, und versucht, ob die Analysatoren diesen Memory leak finden. Die haben aber nichts gemeldet, deswegen, wollte ich wissen, ob also der Memory leak nur dann entsteht, wenn man einen Zeiger mit new erzeugt, dann an eine andere Variable zeigen läßt und anschließend vergißt diesen Zeiger zu löschen. Unten ist der analysiert Quellcode angeführt mit dem Kommentar: // AUF DIESER STELLE WURDE delete pData; EINGEFUEGT - was ich wegen der Analyse ausgeklammert habe. Es wurde also dieses delete pData als memory leak anerkannt:

    case USERCONTROL_CONNOP_TRANSFEROFFSETS:
    			{
    				t_connectiondata_transferoffsets* pData = (t_connectiondata_transferoffsets*)pConnOp->data;
    				buffer = pData->pData;
    				len = pData->len;
    
    				unsigned char* p = buffer + 2;
    				int* userid;
    				__int64* offset;
    				while ((p - buffer + 12) <= len)
    				{
    					userid = (int*)p;
    					offset = (__int64*)(p + 4);
    					t_connectiondata& data = m_UsersList[*userid];
    					data.currentOffset = *offset;
    
    					p += 12;					
    				}
    			// AUF DIESER STELLE WURDE  delete pData; EINGEFUEGT
    			}
    			break;
    		}
    


  • Was genau ist Deine Frage? Weißt Du nicht was ein Speicherleck ist? Oder geht es Dir darum, rauszufinden, nach welchem System Dein "Analyse-Tool" etwas als Speicherleck klassifiziert?

    Ich kenne mich mit solchen Analyse-Tools nicht wirklich aus. Aber es gibt "statische" (begutachten nur den Quellcode) und "dynamische" (beobachten das Verhalten des Programms während es läuft).

    Von einem statischen Analyse-Tool würde ich nicht besonders viel erwarten. In Fällen wie

    int* p = new int;
    p = 0;
    

    sind Speicherlecks relativ leicht aufzuspüren. Es gibt aber sicherlich Speicherlecks, die man mit einem statischen Tool schlecht ausfindig machen kann, sowie falsch positive Diagnosen (etwas wird als Speicherleck identifiziert, ist aber keins).

    Dynamische Tools hingegen protokollieren Speicher-Allozierung und -Freigabe und können Dir sagen, was hinterher noch so alles im Speicher hängt und wahrscheinlich vergessen worden ist.

    Gruß,
    SP



  • Ja, ich will wissen, wann ein Speicherleck entsteht. Ich dachte immer wenn ein Zeiger definiert wird. zB. char* zeiger; muss er nachher auch gelöscht werden.
    In dem Beispiel, den ich im vorigen Beitrag reinkopiert habe, wird der Zeiger pData auch nicht mit new erzeugt, sondern es wurde ihm irgendwelche Adresse einer Variable zugewiesen und trotzdem wurde dann im Change Log vom FileZillaServer (von der auch dieser Quellcodeabschnitt herkommt) angegeben, dass delete pData vergessen wurde, und dass es zu einem memory leak führen würde. Jetzt wollte ich wissen, wann also ein memory leak wirklich entstehen kann? Muss ich einen Zeiger mit new definieren, diesen dann an eine Variable mit einem * Zeichen zeigen lassen zB. zeiger = *variabel; (damit die Adresse in den Zeiger kopiert wird) und erst nachher wenn ich den Zeiger nicht lösche kommt es zu einem Memory leak? Oder warum sollte ich eigentlich den Zeiger mit new definieren?



  • david.dda schrieb:

    Ja, ich will wissen, wann ein Speicherleck entsteht. Ich dachte immer wenn ein Zeiger definiert wird. zB. char* zeiger; muss er nachher auch gelöscht werden.

    Nein, ein Zeiger ist auch nur eine normale Variable. char* zeiger muss genausowenig gelöscht werden wie int zahl . Überhaupt werden nicht Zeiger gelöscht, sondern Speicherblöcke freigegeben und Objekte zerstört.

    In dem Beispiel, den ich im vorigen Beitrag reinkopiert habe, wird der Zeiger pData auch nicht mit new erzeugt, sondern es wurde ihm irgendwelche Adresse einer Variable zugewiesen und trotzdem wurde dann im Change Log vom FileZillaServer (von der auch dieser Quellcodeabschnitt herkommt) angegeben, dass delete pData vergessen wurde, und dass es zu einem memory leak führen würde.

    Ja, der Zeiger wird folgendermaßen initialisiert:

    t_connectiondata_transferoffsets* pData = (t_connectiondata_transferoffsets*)pConnOp->data;
    

    Das heißt, er wird als Kopie von pConnOp->data angelegt. Ob das ein Speicherleck ist oder nicht hängt ganz entscheidend davon ab, was in pConnOp->data drin steht und was mit dem Zeiger später passiert.
    Ich wage mal die kühne Behauptung, dass delete pData; (zumindest aus Design-Perspektive) nicht die Lösung dieses Speicherlecks ist.

    Jetzt wollte ich wissen, wann also ein memory leak wirklich entstehen kann? Muss ich einen Zeiger mit new definieren, diesen dann an eine Variable mit einem * Zeichen zeigen lassen zB. zeiger = *variabel; (damit die Adresse in den Zeiger kopiert wird) und erst nachher wenn ich den Zeiger nicht lösche kommt es zu einem Memory leak? Oder warum sollte ich eigentlich den Zeiger mit new definieren?

    Ein Speicherleck entsteht, wenn du mit new ein Objekt erstellst und dieses Objekt nicht irgendwann mit delete wieder löschst. Wieviele Zeiger zwischendrin auf dieses Objekt zeigen, ist völlig irrelevant. Die Zeiger werden ja auch nicht gelöscht, sondern das Objekt. Mal ein paar Beispiele:

    int a;
    int *p1 = &a; // p zeigt auf die lokale Variable a. kein new also kein delete notwendig
    
    new int; // Objekt wird angelegt, aber die Adresse keinem Zeiger zugewiesen. Wie soll man jetzt noch delete aufrufen können? geht nicht => Speicherleck
    
    int *p2 = new int;
    delete p2; // ok, p2 zeigt auf ein mit new angelegtes Objekt, das wird hier gelöscht
    
    int *p3 = new int;
    p3 = &a; // und was ist mit dem mit new angelegten Objekt? Keine Chance mehr, es freizugeben => Speicherleck
    
    int *p4 = new int;
    int *p5 = p4;
    p4 = 0;
    delete p5; // p5 zeigt auf das mit new angelegte Objekt (zwischendurch haben mal p4 und p5 gleichzeitig darauf gezeigt), das löschen wir hier, alles klar
    


  • david.dda schrieb:

    Ich dachte immer wenn ein Zeiger definiert wird.
    [...]
    Muss ich einen Zeiger mit new definieren
    [...]

    Die Wortwahl ist falsch und deutet auf ein falsches Verständnis von Zeigern hin. Ein Zeiger wird NICHT mit new definiert.

    char* p = new char[100];
    

    Zu beachten: Ds
    a steht ein Gleichheitszeichen zwischen char* p und new. p wird als char* definiert, aber mit new wird der Zeiger initialisiert.

    btw, memory-leaks werden nicht durch den Zeiger selbst verursacht sondern durch new (bei fehlendem delete)

    Ich habe das Fegühl das Du Zeiger mit Referenzen verwechselst...



  • ok, danke sehr, ich hätte einige Bemerkungen zu dem letzten Beispiel - Stimmen diese Behauptungen?

    int *p4 = new int;
    int *p5 = p4;
    p4 = 0;
    delete p5; // p5 zeigt auf das mit new angelegte Objekt (zwischendurch haben mal p4 und p5 gleichzeitig darauf gezeigt), das löschen wir hier, alles klar
    

    int *p4 = new int; -> p4 wurde als ein neues Objekt erstellt - muss gelöscht werden
    int *p5 = p4; -> ein Zeiger auf p4 - der Zeiger p5 wurde nicht mit neu erzeugt - daher muss nicht gelöscht werden
    p4 = 0; -> p4 zeigt auf andere Adresse - kann daher mit delete p4 nicht mehr gelöscht werden - daher würde ein Speicherleck entstehen
    delete p5; -> damit der Speicherleck nicht entsteht, löscht man die Adresse von p4, die in p5 gespeichert wurde. (das Objekt, dass unter dieser Adresse erzeugt wurde)

    Ich habe noch einige Unklarheiten: warum erstellt man mit einem Zeiger direkt ein Objekt? Ich glaubte, ein Objekt wird erstellt (z.B. Person p=new Person(); ) und der Zeiger zeigt nur darauf hin (z.B. Person *z = &p; ). Was ist der Sinn des Erzeugens eines Objektes mit einem Zeiger? - (z.B. Person *neu = new Person(); ) - bedeutet diese Initialisierung, dass ein Objekt Person erzeugt wird, irgendwo im Speicher abgelegt wird und nur durch den Zeiger erreicht werden kann? - sprich - es ist gleich wie ( Person p=new Person(); mit Person *z = &p; ) mit dem Unterschied, dass beim "Person *neu = new Person();" "neu" irgendwo im Hintergrund gespeichert wurde und kann nicht mehr zugegriffen werden aber nur mit dem Zeiger z angesprochen werden?



  • Was ist der Sinn des Erzeugens eines Objektes mit einem Zeiger?

    Man erstellt mit einem Zeiger kein Objekt.

    new fordert Speicher für ein Objekt im freien Speicher an, der allerdings unbenannt ist. Die einzige Möglichkeit auf diesen Speicher zuzugreifen, ist über einen Zeiger.

    MfG,
    ScRaT



  • Sebastian Pizer schrieb:

    Schau nochmal in Dein C++ Buch rein. Lies Dir die Kapitel über Zeiger und dynamische Speicherverwaltung nochmal durch.

    Lern überhaupt erstmal die Grundlagen von C++. Dein mentales Modell von dem, was bei C++ so abgeht, scheint ganz schön verzerrt zu sein. Ich kann nur für mich sprechen, aber bei mir geht die Motivation sehr schnell runter, wenn ich merke, dass der Hilfesuchende von Tuten und Blasen keine Ahnung hat. Man kann Dir so schlecht helfen, wenn Du nicht mal dieselbe Sprache sprichst wie wir und es ständig Missverständnisse gibt. Der Verweis auf ein gutes Lehrbuch, was Du lesen solltest, schlägt 2 Fliegen mit einer Klappe: (1) Du entlastest uns, indem Du Dir selbst hilfst. (2) Dir wird viel besser geholfen, lernst wichtige Grundlagen, die richtige Terminologie etc. Mit trial-and-error kommst Du bei C++ nicht weit.

    Gruß,
    SP



  • david.dda schrieb:

    Stimmen diese Behauptungen?

    int *p4 = new int;   // p4 wurde als ein neues Objekt erstellt - muss gelöscht werden
    int *p5 = p4;        // ein Zeiger auf p4 - der Zeiger p5 wurde nicht mit neu erzeugt - daher muss nicht gelöscht werden
    p4 = 0;              // p4 zeigt auf andere Adresse - kann daher mit delete p4 nicht mehr gelöscht werden - daher würde ein Speicherleck entstehen
    delete p5;           // damit der Speicherleck nicht entsteht, löscht man die Adresse von p4, die in p5 gespeichert wurde. (das Objekt, dass unter dieser Adresse erzeugt wurde)
    

    Nein, alles falsch. Da kann jemand "Pointer" und "Pointee" nicht auseinander halten. Das scheint die Wurzel Deiner Verständnisprobleme zu sein.

    int *p4 = new int;  // p4 ist ein Zeiger, der auf ein dynamisch
                        // alloziertes int-Objekt zeigt
                        // p4 wird automatisch gelöscht! Das, worauf p4 zeigt nicht!
                        // p4 wurde nicht mit new angelegt! Das, worauf p4 zeigt schon!
    int *p5 = p4;       // p5 zeigt jetzt auf dasselbe Objekt wie p4
                        // p5 zeigt nicht auf  p4 !
                        // p5 zeigt       auf *p4 (im Moment) !
    p4 = 0;             // p4 zeigt auf nichts mehr
    delete p5;          // das int-Objekt wird gelöscht, weil wir die Adresse noch
                        // in p5 gespeichert haben.
    

    Gruß,
    SP



  • david.dda schrieb:

    Ich habe noch einige Unklarheiten: warum erstellt man mit einem Zeiger direkt ein Objekt?

    Du meinst, warum man int* p = new int; schreibt? Naja, du kannst auch erst den Zeiger definieren und dann zuweisen: int *p; p = new int; aber aus einer Reihe von guten Gründen bevorzugt man die Initialisierung.

    Ich glaubte, ein Objekt wird erstellt (z.B. Person p=new Person(); ) und der Zeiger zeigt nur darauf hin (z.B. Person *z = &p; ).

    Wo hast du denn das her? Das erste funktioniert ja schonmal gar nicht. Wenn du Person p = ... schreibst, deklarierst du p als Objekt vom Typ Person . new Person() erstellt aber ein neues Objekt vom Typ Person auf dem Freispeicher und liefert die Adresse dieses Objekts (d.h. einen Zeiger darauf zurück). Du kannst aber den Zeiger nicht an p zuweisen, p ist ja kein Zeiger.

    Was ist der Sinn des Erzeugens eines Objektes mit einem Zeiger? - (z.B. Person *neu = new Person(); ) - bedeutet diese Initialisierung, dass ein Objekt Person erzeugt wird, irgendwo im Speicher abgelegt wird und nur durch den Zeiger erreicht werden kann?

    Genau, und noch mehr: Das erzeugte Person-Objekt bleibt solange gültig, bis es mit delete zerstört wird. Die Alternative zum Verwenden von new (die du immer wieder falsch wiedergibst, da muss ich jetzt auch mal dringend zu einem vernünftigen Lehrbuch raten) funktioniert so:

    Person p; // ein Objekt vom Typ Person wird erzeugt und p genannt
    

    Diese Objekte werden zerstört, wenn der Gültigkeitsbereich von p verlassen wird, deshalb nennt sich das auch automatische Speicherdauer:

    int main() {
      Person p; // nix new
      p.bla();
    } // hier hört p auf zu existieren, es wird automatisch der Destruktor aufgerufen
    


  • david.dda schrieb:

    Person p = new Person();

    Nur so auf Verdacht: C++ != Java. Diese Sprachen bitte nicht durcheinander werfen. Was die Speicherverwaltung, Erzeugung von "Objekten", "Referenzen" und das Objekt-Modell angeht, unterscheiden sich diese Sprachen gewaltig.



  • Ich habe schon einige Bücher über C++ gelesen, aber weil es nur viel Theorie ohne Praxis war, versteht man vieles nicht so eindeutig. Jedenfalls werde ich mir noch das Buch besorgen. Was ich fragen wollte:
    Hier im Quellcode wird ein Zeiger pData erstellt. Dieser zeigt auf einen Struct, der im zweiten Teil abgebildet ist.

    case USERCONTROL_CONNOP_TRANSFEROFFSETS:
    			{
    				t_connectiondata_transferoffsets* pData = (t_connectiondata_transferoffsets*)pConnOp->data;
    				buffer = pData->pData;
    				len = pData->len;
    
    				unsigned char* p = buffer + 2;
    				int* userid;
    				__int64* offset;
    				while ((p - buffer + 12) <= len)
    				{
    					userid = (int*)p;
    					offset = (__int64*)(p + 4);
    					t_connectiondata& data = m_UsersList[*userid];
    					data.currentOffset = *offset;
    
    					p += 12;					
    				}
    				// DA SOLLTE EINGEFÜGT WERDEN: delete pData;
    			}
    			break;
    		}
    

    Struct für pData

    typedef struct
    {
    	void *data;
    	int op;
    	int userid;
    } t_connop;
    

    pConnOp (dass pData definiert: t_connectiondata_transferoffsets* pData = (t_connectiondata_transferoffsets*)pConnOp->data;) wird vom dem Eingabeparameter in der gleichen Methode übernohmen, wobei LPARAM ein _W64 long ist:

    LRESULT CServer::OnServerMessage(CServerThread* pThread, WPARAM wParam, LPARAM lParam)
    {
    t_connop *pConnOp = reinterpret_cast<t_connop*>(lParam);
    ...
    

    und die Methode OnServerMessage wird so verwendet:

    std::list<CServerThread::t_Notification> notifications;
    			pThread->GetNotifications(notifications);
    			for (std::list<CServerThread::t_Notification>::const_iterator iter = notifications.begin(); iter != notifications.end(); iter++)
    				if (pServer->OnServerMessage(pThread, iter->wParam, iter->lParam) != 0)
    					break;
    

    Ich kann hier also keinen Grund finden, warum pData wirklich gelöscht werden sollte, da kein Objekt erzeugt wird.



  • david.dda schrieb:

    Ich habe schon einige Bücher über C++ gelesen,

    welche?

    david.dda schrieb:

    Jedenfalls werde ich mir noch das Buch besorgen.

    welches?

    Sorry, aber Deine Glaubwürdigkeit ist, wegen dem, was Du so von Dir gibst, nahe Null. Ein Tipp für's nächste mal: Wenn Du demnächst irgendwo nochmal eine Frage stellst, könntest Du auch dein Erfahrungs- und Wissensstand verraten. Diese Info kann nie schaden und erleichtert es womöglich den Hilfsbereiten deine Fragen besser einzuordnen.

    david.dda schrieb:

    Was ich fragen wollte:
    [...code_fragment...]
    Ich kann hier also keinen Grund finden, warum pData wirklich gelöscht werden sollte, da kein Objekt erzeugt wird.

    Das kann man gar nicht anhand dieses kleinen Code-Fragments beurteilen. Man müsste schon die Zusammenhänge kennen. Wo ist das dazugehörige new? Was hat sich der Programmierer dabei gedacht? Ist es irgendwo dokumentiert, wie die Speicherverwaltung der Puffer in diesem Kontext gedacht ist? u.s.w.

    Gruß,
    SP



  • Du mußt noch weiter im Code suchen, nämlich da, wo die Elemente der Liste 'std::listCServerThread::t_Notification' erzeugt werden... und dort wird es wohl eine Speicherallokation für 'lParam->data' geben.
    (ist aber alles andere als schöner Code, da wären shared_pointer sicherlich besser - außerdem ist das m.E. die falsche Stelle: warum wird das nicht im Destruktor von CServerThread::t_Notification gemacht???)



  • danke für den Hinweis, der "iterator" hat die Liste "notifications" durchgelaufen:

    std::list<CServerThread::t_Notification> notifications;
    			pThread->GetNotifications(notifications); //da muss die Speicherallokation für 'lParam->data' sein
    			for (std::list<CServerThread::t_Notification>::const_iterator iter = notifications.begin(); iter != notifications.end(); iter++)
    				if (pServer->OnServerMessage(pThread, iter->wParam, iter->lParam) != 0)
    					break;
    

    Die Liste wurde mit "GetNotifications(notifications)" erstmals gefüllt (dabei wurde der Inhalt dieser Liste mit der Liste "m_pendingNotifications" umgetauscht:

    void CServerThread::GetNotifications(std::list<CServerThread::t_Notification>& list)
    {
    	EnterCritSection(m_threadsync);
    
    	m_pendingNotifications.swap(list);
    
    	if (m_throttled)
    		SetPriority(THREAD_PRIORITY_NORMAL);
    
    	LeaveCritSection(m_threadsync);
    }
    

    und die Liste "m_pendingNotifications" wurde wiederum so gefüllt:

    void CServerThread::SendNotification(WPARAM wParam, LPARAM lParam)
    {
    	EnterCritSection(m_threadsync);
    	t_Notification notification;
    	notification.wParam = wParam;
    	notification.lParam = lParam;
    
    	if (m_pendingNotifications.empty())
    		PostMessage(hMainWnd, m_nNotificationMessageId, 0, 0);
    
    	m_pendingNotifications.push_back(notification);
    
    	// Check if main thread can't handle number of notifications fast enough, throttle thread if neccessary
    	if (m_pendingNotifications.size() > 200 && m_throttled < 3)
    	{
    		SetPriority(THREAD_PRIORITY_IDLE);
    		m_throttled = 3;
    	}
    	else if (m_pendingNotifications.size() > 150 && m_throttled < 2)
    	{
    		SetPriority(THREAD_PRIORITY_LOWEST);
    		m_throttled = 2;
    	}
    	else if (m_pendingNotifications.size() > 100 && !m_throttled)
    	{
    		SetPriority(THREAD_PRIORITY_BELOW_NORMAL);
    		m_throttled = 1;
    	}
    
    	LeaveCritSection(m_threadsync);
    }
    

    Diese Methode "SendNotification" wurde dann mehrmals benutzt, hier ist ein Beispiel:

    t_connop *op = new t_connop;
    	op->data = 0;
    	op->op = USERCONTROL_CONNOP_REMOVE;
    	op->userid = m_userid;
    	m_pOwner->SendNotification(FSM_CONNECTIONDATA, (LPARAM)op);
    

    Es wurde also ein Zeiger "op" erstellt, der einen struct mit new erzeugt:

    typedef struct
    {
    	void *data;
    	int op;
    	int userid;
    } t_connop;
    

    Deswegen musste dann dieses neues struct-Objekt, an dem "op" Zeiger hinweist, gelöscht werden. Ich hoffe, es stimmt so.

    Antwort zu der vorigen Frage:
    Ich habe C++Tutorial.pdf (ca. 140 Seiten) und Teach Yourself C++ in 21 days (da habe ich einige Teile übersprungen) und dann noch ziemlich viel Online, gelesen (zuletzt tutorial vom schornboeck nochmals über die Zeiger und dynamische Speicherreservierung). Ich habe mich ca. 2 Jahre privat mit Java beschäftigt und schon auch einiges programmiert (z.B. einen Tetris Spiel) und seit einem halben Jahr mit C++, aber eher viel theoretisch und nur mal sehr kleine Applikation ausprobiert - wie einen Taschenrechner mit Hilfe von Visual Studio. Deswegen scheinen Dir meine Fragen vielleicht so primitiv. In einem halben Jahr bin ich sicher wieder bißchen weiter.



  • david.dda schrieb:

    Antwort zu der vorigen Frage:
    Ich habe C++Tutorial.pdf (ca. 140 Seiten) und Teach Yourself C++ in 21 days (da habe ich einige Teile übersprungen) und dann noch ziemlich viel Online, gelesen (zuletzt tutorial vom schornboeck nochmals über die Zeiger und dynamische Speicherreservierung). Ich habe mich ca. 2 Jahre privat mit Java beschäftigt und schon auch einiges programmiert (z.B. einen Tetris Spiel) und seit einem halben Jahr mit C++, aber eher viel theoretisch und nur mal sehr kleine Applikation ausprobiert - wie einen Taschenrechner mit Hilfe von Visual Studio.

    Da ich nicht besonders viel von C++-Onlinetutorials halte, würde ich dir auch zu einem gescheiten Buch wie z. B. dem C++-Primer raten. Weil du ja auch folgendes geschrieben hattest:

    david.dda schrieb:

    Ich habe schon einige Bücher über C++ gelesen, aber weil es nur viel Theorie ohne Praxis war, versteht man vieles nicht so eindeutig.

    würde ich dir das Buch auch deswegen empfehlen, weil du dort Unmengen an Übungsaufgaben findest an denen du dich versuchen kannst. 🙂

    PS: Wer weiß, wenn du deine Eltern/Verwandten/Bekannten darauf ansprichst, dann kriegst du es vielleicht als Weihnachtsgeschenk. :xmas1:



  • Hallo david.dda,

    die Freigabe des Speichers bezieht sich aber auf eine evtl. Zuweisung von "op->data = static_cast<void *>(new X);". Gibt es auch solche (oder ähnliche) Speicherallokationen?

    Aber wie schon geschrieben, ist das keine gute Implementierung, anscheinend nur ein Notbehelf, um Speicherlecks zu fixen...
    Edit: und auch sehr fehleranfällig, falls z.B. konstante Zuweisungen á la

    op->data = (void *)42;
    // oder
    op->data = (void *)"hello";
    

    passieren (habe extra mal kein static_cast benutzt, um zu zeigen, was alles so programmiert werden könnte...)


Anmelden zum Antworten