ubuntuusers.de

Probleme in C++ mit delete

Status: Gelöst | Ubuntu-Version: Ubuntu 18.04 (Bionic Beaver)
Antworten |

umbrella_cop.

Anmeldungsdatum:
29. März 2012

Beiträge: 153

Wohnort: Aachen / Brand

Hallo Zusammen

Ich habe eine kleine, vermutlich ziemlich einfach zu lösende Frage bezüglich des "delete" in meinem C++ Code.

Zuerst die Intension... Ich wollte einen Gerichteten Graphen Programmieren, der dann in ein Größeres Projekt einfließen soll. der dort benutzte Datentyp ist Variabel, daher template's

Da ich noch relativ frisch in der C++ Gegend angle, verzeiht mir wenn ich mit dem Code in dem Trüben fische.

Ich habe in den Code verweise eingebaut (/*xyz*/) an denen ich mich bei der Fragestellung Orientiere. Und hier mein Code (Graph.h):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#include <iostream>
#include <list>

template<class T>
class Graph
{


public:
	T element;
	std::list<Graph<T>*> childs;
	std::list<Graph<T>*> parents;
	Graph(T);
	~Graph();
	bool makeChild(Graph<T>*);
	bool deleteChild(Graph<T>*);
	bool makeParent(Graph<T>*);
	T getElement();
	bool leaf;
};

template<class T>
Graph<T>::Graph(T element) : element(element)
{
	leaf = true;
}

template<class T>
Graph<T>::~Graph()
{
    if(!leaf)
        {
/*4*/       for (auto it = childs.begin(); it != childs.end();)
		{
			// wenn das kind nicht mehrere Väter hat, denen ich es nicht weg nehmen will
			if ((**it).parents.size()<2)
				{
/*5*/				delete *it ++;
				}
				else{
					it ++;
				}
			}
        }
	if (!(*this).parents.empty())
    {
/*6*/    for (auto it = parents.begin(); it != parents.end(); it++)
    	{
    		//alle Väter vergessen dieses Kind, damit es in ohne folgen beseitigt werden kann
    		(**it).deleteChild(this);
    	}
    }
}

template<class T>
T Graph<T>::getElement()
{
	return (*this).element;
}

template<class T>
bool Graph<T>::deleteChild(Graph<T>* tokill)
{
	for (auto it = childs.begin(); it != childs.end(); it++)
	{
		if( (*it)==tokill){
			childs.erase(it);
			return true;
		}
	}
	// Error code hier einfügen
	std::cout<<"Leider dieses Kind nicht gefunden. Error main2.h at line 61"<<std::endl;
	return false;
}

//eingane der zu setzende Vater. Wenn setzen des Vaters gelingt, wird er in die Liste der Väter aufgenommen
template<class T>
bool Graph<T>::makeParent (Graph<T>* newParent){
	if ((*newParent).makeChild(this)){
		parents.push_back(newParent);
		return true;
	}
	else{
		//Error code hier einfügen
		std::cout<<"das Erzeugen dieses Kindes bei dem Vater war nicht möglich. Error main2.h at line 76"<<std::endl;
		return false;
	}
}

template<class T>
bool Graph<T>::makeChild(Graph<T>* inTree)
{
	childs.push_back(inTree);
	(*inTree).parents.push_back(this);
	leaf = false;
	return true;
}

Zum testen habe ich dann auch noch eine main geschrieben, die Hier ist (main.cpp):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include "Graph.h"
#include <iostream>
#include <string>
#include <memory>
int main (){
        {
                int count = 0;
/*		wenn new geht, wird das wieder aktiviert. solange inaktiv
                std::shared_ptr<Graph<int>> test(new Graph<int>(12));
*/
/*1*/	        Graph<int>* test = new Graph<int>(12);
/*2*/           for (int i = 0; i<2;i++){
                (*test).makeChild(new Graph<int>(9));
                (*test).makeChild(new Graph<int>(18));}
                for (auto i = (*test).childs.begin(); i != (*test).childs.end() ;i++)
                {
                        std::cout <<"Das Element " << (*test).getElement() << ":" << count << " ist " << (**i).getElement() << ". Ist es ein Blatt?: " << ((**i).leaf? "yes" : "no") << std::endl;
                        count ++;
                }
                count = 0;
/*3*/           delete test;
        }
}

Soweit zu dem...

Nun zu den Vermerken:

1) Erzeugen eines neuen Graphen und einen Pointer auf ihn (test)

2) 4 Knoten erstellen, die alle unter Knoten "19" sind mit new (ansonsten wehren die ja sofort wieder weg)

3) Sollte test Löschen, und damit ~Graph() aufrufen und den Speicher frei geben (Spoiler, das mit dem Speicher macht er nicht)

4) Wenn ein Knoten Gelöscht wird, werden auch alle Kinder gelöscht mit nur einem Vater

5) sollte das Kind löschen und damit vom Kind ~Graph() aufrufen und Speicher frei geben (Spoiler, auch hier das gleiche wie bei 3) )

6) Löscht sich aus der Liste childs von seinen Vätern raus. Nun sollte kein Pointer mehr auf den Speicher zeigen innerhalb des Graphen, bedenkenloses löschen möglich!

Wenn ich das jetzt ausführe wird des Speicher aber nicht gelöscht ... warum denn ... ich verstehe das nicht ...

Wehre unglaublich nett wenn ihr mir dabei helfen könntet ☺

Grüße EvD

Ps.: Mir geht es darum etwas zu lernen. Ich lerne nur wenig wenn ihr mir sagt ich solle das einfach includen, oder ihr ein Programm von euch Postet (da lerne ich wenigstens noch n bisschen was) Bitte einfach einen Tipp geben wo da der Fehler ist ☺

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4673

Wohnort: Berlin

@umbrella_cop.: Also wenn ich das kompiliere und mit Valgrind ausführe, dann sehe ich da kein Speicherleck‽ Warum glaubst Du da wäre eines?

$ valgrind ./a.out 
==7189== Memcheck, a memory error detector
==7189== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==7189== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==7189== Command: ./a.out
==7189== 
Das Element 12:0 ist 9. Ist es ein Blatt?: yes
Das Element 12:1 ist 18. Ist es ein Blatt?: yes
Das Element 12:2 ist 9. Ist es ein Blatt?: yes
Das Element 12:3 ist 18. Ist es ein Blatt?: yes
==7189== 
==7189== HEAP SUMMARY:
==7189==     in use at exit: 0 bytes in 0 blocks
==7189==   total heap usage: 13 allocs, 13 frees, 216 bytes allocated
==7189== 
==7189== All heap blocks were freed -- no leaks are possible
==7189== 
==7189== For counts of detected and suppressed errors, rerun with: -v
==7189== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) 

umbrella_cop.

(Themenstarter)

Anmeldungsdatum:
29. März 2012

Beiträge: 153

Wohnort: Aachen / Brand

ich habe mal folgendes gemacht im main.cpp ab Line 21 ...

1
2
3
4
5
6
7
8
.
.
.
delete test;
std::cin>>count;
.
.
.

und habe beim debugger bei dem cin gestoppt und mal die RAM-Auslastung angeschaut ... und da ist sie nicht ein Stück gesunken

Hier habe ich das mal aufgenommen aufgenommen ... habe ich das mit delete dann falsch verstanden und der Speicher wird erst ab dem ende des Programmes Frei gegeben ? Das wehre aber komisch ...

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4673

Wohnort: Berlin

@umbrella_cop.: Nach der RAM-Auslastung kannst Du nicht gehen. Ob da RAM dem Betriebssystem zurückgegeben wird, und falls ja, wann, ist eine ganz andere Frage. Zudem wird man ziemlich sicher die 216 Bytes die das Programm da belegt und wieder freigegeben hat, nicht in dem Graphen sehen können, selbst wenn das dem Betriebssystem wieder zurückgegeben werden sollte.

Wenn Du wissen willst ob Du ein Speicherleck hast, dann musst Du eine entsprechende Bibliothek einbinden oder so etwas wie Valgrind verwenden.

Der Speicher wird für Dein Programm wieder freigegeben. Nichts anderes garantiert ein delete bzw. das freigeben von Speicher innerhalb eines Programmlaufs.

umbrella_cop.

(Themenstarter)

Anmeldungsdatum:
29. März 2012

Beiträge: 153

Wohnort: Aachen / Brand

ah ja, ich habe vergessen zu erwähnen das ich in der for schleife die 2 durch 2000000 ersetzt habe (das ist der peek, der bei dem Bild zu sehen ist).

Aber es ist ganz nett zu wissen das ich nicht nach dem RAM gehen kann. dann Danke ich mal für die Hilfe ☺

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13174

Wenn das Thema damit erledigt ist, bitte markiere als "gelöst". Danke!

Antworten |