Willkommen ~Gast!
Registrieren || Einloggen || Hilfe/FAQ || Staff
Probleme mit der Registrierung im Forum? Melde dich unter registerEin Bild.
Autor Beitrag
050
05.12.2002, 09:11
Kriz



Hä?

Der macht was? Eine Liste nach leeren Objekten durchsuchen? Was verstehst du unter leeren Objekten? Wenn ein Element aus der Liste entfernt wird durch remove() o.ä. , dann sollte auch zugesichert sein, daß dieses Element auch durch die Listenverwaltung vollständig vom Heap gelöscht wurde. Nur einfach das Element aus der Liste entlassen bringt nichts, da du sonst ein "verwaistes Objekt" auf dem Heap rumliegen hast, das nur Speicherplatz verschwendet und zu dem du absolut keinerlei Zugriff mehr hast zum nachträglichen Löschen!

Leere Objekte, also Elemente ohne Inhalt, sollten tunlichst nicht in der Liste länger verweilen als nötig, da die Liste sonst unnötig aufgebläht wird (Speicher frisst) und die relative Zugriffszeit ebenfalls erhöht wird. Leere Objekte ans Ende der Liste zu transferieren bringt dir nämlich garnichts, denn normalerweise werden neue Elemente ans Ende angehängt. Wenn du allerdings durch deinen "Manager" bereits z.B. 200 leere Elemente ans Ende bewegt hast, dann müßte deine Liste theoretisch bei einem toBegin() o.ä. erstmal 200 leere, nutzlose Elemente durchgehen plus die vorderen Elemente der Liste, da der Zeiger auf das aktuelle Element (normalerweise) beim Hinzufügen eines Elements auf dasselbige zeigt.

Anderer Punkt: Wenn du ein Element aus der List entfernst (also definitiv löschst), kannst du niemals sicher sein, das der dort freigegebene Platz auch wieder zum Füllen mit einem neuen Element bereitsteht. Die Heapverwaltung übernimmt das RTS (Runtime System) des Programms und darauf hast du keinen Einfluß.

Geschwindigkeitsmäßig sollte eine Liste nur dann genommen werden, wenn dynamischen Arrays oder sowas benutzt werden sollen. Denn das Umkopieren dynamischer Strukturen wie Arrays infolge einer Hinzufügung ist zeitaufwendiger als das Hinzufügen eines Listenelements. Anders sieht das bei statischen Arrays aus. Dort ist mittels Zeigerarithmetik der Zugriff schneller als mit einer Liste.

--

K:R-I)Z++
"CSS ist cascading style sheets. Und nicht so'n Ranzspiel." - dp
In memory of Voice († 2005/03/30)

zum Seitenanfang zum Seitenende Profil || Suche
051
05.12.2002, 09:51
King of Darkness



ok danke, das hilft mir etwas weiter,
mit leeren objekten meinte ich zb einen paritkle der nicht mehr gebraucht wird, also habe ich immer noch einen zeiger auf das objekt, nur brauche ich die daten nicht mehr die da drin sind,
aber mal was anderes reicht es wenn ich mit free(zeiger) den speicher frei geben oder sollte ich da noch irgendwas mehhr machen ?

--

Coding Center --- Tutorials über Programmierung und andere Themen
Amazon Preisbeobachung mit Preisalarm

zum Seitenanfang zum Seitenende Profil || Suche
052
05.12.2002, 15:06
Prefect



Alles was du malloc()st mußt du auch free()en.
Um ein Element aus einer Linked List zu entfernen mußt du zuerst die Pointer neu verstricken damit niemand mehr auf das Element zeigt, dann free()st du es.

"Leere" Elemente in einer Liste zu lassen ist unsinnig, das erhöht nur den Verwaltungsaufwand, lieber gleich free()en.

Andererseits gibt es Situationen, in denen du dich durchaus um die Speicherverwaltung sorgen mußt. malloc() und free() können recht langsam sein, dazu kommt dann auch noch eine Heapfragmentation wenn du kleine Strukturen andauernd löscht und wieder erstellst.
In solchen Fällen kann es unter Umständen sinnvoll sein eine zweite Liste mit unbenutzten Strukturen zu verwenden. Wenn du dann ein neues Element in die eigentliche LL einfügen willst mußt du malloc() nur aufrufen, wenn die zweite Liste leer ist.

Diese Methode mit der Empty-List ist durchaus machbar, in deinem Fall (Partikelsystem) aber nicht unbedingt sinnvoll. Für ein Partikelsystem könntest du zum Beispiel ein ungeordnetes dynamisches Array verwenden. Da sind, genauso wie bei einer LL, Löschen und Einfügen O(1)-Algorithmen. Allerdings entfällt der Aufruf der Heaproutinen, die sehr unberechenbar sind. Außerdem befinden sich alle Partikel in einem zusammenhängenden Speicherbereich - der Cache wird es dir danken.

cu,
Prefect

--

Widelands - Gemütliche Aufbaustrategie, Free Software
Noch ein Blog - Lerne, wie die Welt wirklich ist, aber vergiss niemals, wie sie sein sollte.

zum Seitenanfang zum Seitenende Profil || Suche
053
05.12.2002, 15:16
King of Darkness



mhhh auch ne möglichkeit nur habe ich mit nem dynamischen array noch nicht gearbeitet, wie funktioniert sowas

objekt *array[];

oder wie ?

um nochmal zur liste zu kommen, ich habe ein problem wie man ja weis ;) und zwar wenn ich das ding free()e dann is ds teil immer nochdrin, gedanken habe ich mir da schon gemacht aber da kommt nur müll raus:

pObjekt->next = pObjekt->next->next;
free(pObjekt->next->before);
pObjekt->next->before = pObjekt;

nur geht das irgendwie nich :(
was mag der da nicht, oder muss ich da jede einzenen objektdaten neu addressieren und dann auch jedes einzelne objektdaten free()en ?

komisches satz das sein !

--

Coding Center --- Tutorials über Programmierung und andere Themen
Amazon Preisbeobachung mit Preisalarm

zum Seitenanfang zum Seitenende Profil || Suche
054
06.12.2002, 09:06
Kriz



Ich mach mal ne C Variante:

Quellcode:int remove(struct Element *pElement)
{
    if(!pElement) return 0;
    else
    {
        struct Element *pNext = pElement->next;
        struct Element *pPrev = pElement->prev;
        free(pElement);
        if(pPrev) pPrev->next = pNext;
        if(pNext) pNext->prev = pPrev;
        toEnd(g_pActualElement);
        return 1;
    }
}

Was tut sich hier? Zuerst wird mal geprüft, ob der übergebene Elementzeiger ungleich NULL ist, also existiert (eine Funktion create() z.B. erledigt das Erzeugen eines neuen Elements, welches dann ja ungleich NULL wird). Wenn ja, dann werden zwei Hilfszeiger pNext und pPrev erzeugt. pNext zeigt auf den Nachfolger des Elements, während pPrev auf dessen Vorgänger zeigt. Hier spielt es keine Rolle, ob der Nachfolger und/oder Vorgänger NULL ist. Jetzt ist die Verkettung erstmal gesichert. Danach wird das Element gelöscht. Anschließend wird geprüft, ob der Vorgänger existiert. Falls ja, wird der next-Zeiger des Vorgängers auf den Nachfolger gerichtet. Das gleiche passiert umgekehrt mit dem Nachfolger, der auf den Vorgänger des Elements gerichtet wird. Danach setzt eine Funktion toEnd() den globalen (!) AktuellesElement Zeiger auf das letzten, verfügbare Element der Liste. Das ist sicherer als das aktuelle Element auf den Nachfolger oder Vorgänger des gelöschten Elements zu setzen. Aber das kannst du ja realisieren wie du willst.

--

K:R-I)Z++
"CSS ist cascading style sheets. Und nicht so'n Ranzspiel." - dp
In memory of Voice († 2005/03/30)

zum Seitenanfang zum Seitenende Profil || Suche
055
06.12.2002, 15:16
Prefect



Das dynamische Array sieht in etwa so aus:

Quellcode:
Object* array = 0;  // das eigentliche Array
int array_size = 0; // Anzahl Elemente im Array
int array_reserved = 0; // Für wie viele Elemente wurde Speicher reserviert?

Auf die einzelnen Elemente im Array kannst du dann ganz normal mit array[n] zugreifen.
Einfügen und Löschen von Elementen sieht im Pseudocode etwa so aus:

Quellcode:
int allocate()
{
  if (array_size >= array_reserved)
    Per realloc() neuen Speicher reservieren und array_reserved entsprechend anpassen

  array_size++;

  return array_size - 1; // der Rückgabewert ist der Index des neuen Elements
}

void remove(int index)
{
  if (index < array_size-1) {
    Kopiere array[index] = array[array_size-1];
  }
  array_size--;
}

Natürlich sollte das Array bei Gelegenheit auch wieder verkleinert werden (mit realloc()) wenn array_size sehr viel kleiner ist als array_reserved. Allerdings macht es durchaus Sinn, komfortabel viel Platz frei zu lassen damit man realloc() nicht so oft aufrufen muß - realloc() kann sehr teuer kommen, weil es potentiell das ganze Array in der Gegend herumkopiert.

Auch mußt du berücksichtigen, daß die Elemente von remove() verschoben werden, d.h. die Indizes sind nicht konstant.

Für ein Partikelsystem, bei dem die Indizes keine Rolle spielen, ist ein solches dynamisches Array allerdings ganz günstig.

Prinzipiell kannst du übrigens auch das std::vector-Template verwenden. Allerdings kriegst du optimale Performance wahrscheinlich nur, wenn du das Array per Hand managest und einen besser angepaßten Algorithmus verwendest um zu entscheiden, wann das Array per realloc() vergrößert oder verkleinert werden soll.

cu,
Prefect

--

Widelands - Gemütliche Aufbaustrategie, Free Software
Noch ein Blog - Lerne, wie die Welt wirklich ist, aber vergiss niemals, wie sie sein sollte.

zum Seitenanfang zum Seitenende Profil || Suche
056
06.12.2002, 16:32
the_viking



Bei Partikel-systemen würd ich warten, bis das ganze tot ist und dann das GANZE array entfernen, stell dir vor du müsstes alle 10ms 1 von 1000 partikeln entferenen.. und sooo groß ist der speicherbedarf nun auch nicht....

bei 1000 partikeln, á la:
Quellcode:
class CParticle
{
TVector m_Position;
TVector m_Direction;
TVector m_OldPosition;
float m_Energy;
TVector m_Color;
};

mehr braucht man da auch nicht drin. Das wären dann:
für jedes TVector = 4 * sizeof(float) = 4 * 4 = 16
für jedes float = 4 = 1*4 = 4
= 20 Byte für jedes partikel = 1000 * 20 = 20000 Byte für ein PSystem
= 20000 / 1024 = 19 kb

WER SICH UM DIESE 19!KB GEDANKEN MACHT, SOLLTE MAL ZUM PSYCHATER!!! ( auf einem 128MBRam-frei rechner könnte man dan ca. 7000 Partikel-Systeme laufen lassen, ausser man benutzt HW-VertexBuffer)

--

thx, cu, MfG the_viking

(( My =]=H=O=M=E=> Page! ))
Coder bei Brainshock-Interactive und bei Z-Software
My ICQ: #160959446

zum Seitenanfang zum Seitenende Profil || Suche
057
06.12.2002, 20:40
Prefect



Anscheinend hast du die von mir vorgeschlagene Methode nicht wirklich verstanden. Wie gesagt, remove() und insert() sind _beides_ O(1)-Algorithmen.

Wenn du die Partikel nicht entfernst erhältst du ein fragmentiertes Array, und du mußt dich darum kümmern welche Partikel-Struktur nun ein gültiges Partikel enthält und welches nicht. Außerdem wird die insert()-Operation um einiges komplexer, weil du erst nach nicht verwendeten Partikel-Strukturen suchen mußt.

Übrigens würde ich auch nicht jedes Mal, wenn ein Partikel eingefügt oder gelöscht wird eine Heapmanagement-Routine aufrufen (habe ich auch nie behauptet), denn das wäre _natürlich_ dumm. Wenn auch die Argumentation über den Speicherplatz etwas lame ist, ich würde da eher über die Unberechenbarkeit (performance-mässig) von Heaproutinen argumentieren. Whatever...

BTW, deine Rechnung ist inkorrekt. Wenn ein Vektor aus 3 floats besteht braucht die von dir gezeigte Struktur 4 * (3*4) + 4 = 52 Bytes.

cu,
Prefect

--

Widelands - Gemütliche Aufbaustrategie, Free Software
Noch ein Blog - Lerne, wie die Welt wirklich ist, aber vergiss niemals, wie sie sein sollte.

zum Seitenanfang zum Seitenende Profil || Suche
058
09.12.2002, 09:26
King of Darkness



mal jetz mal wieder zu meiner linked list
sie geht :D aber nicht ordentlich :(, um genauer zu sein wenn ich mit free() den speicher frei geben will dann behällt das proggi sich aber den speicher, wenn ich dann wieder neue objekt zu weise dann nimmt es sich wieder neuen speicher wo is da sein problem, mal zu aufbau meiner liste:

class objekt
{
char *zeichen;
}
class liste
{
objekt *pDaten;
liste *pNext;
liste *pBefore;
unsigned long Index;
}
class objektliste
{
liste *pErstes;
liste *pObjekt;
liste *pLetztes;
liste *Next; //tempzeiger
liste *Before; //tempzeiger

unsigned long Länge;
}

es ist nich alles nur das was ich noch im kopf habe ;)
sollte aber reichen denke ich mal, ich habe auch noch funktinen drin,
im destrukter der klassen free ich jeden zeiger
aber trotzdem "verschwendet" er den speicher (?)
wo is das problem

--

Coding Center --- Tutorials über Programmierung und andere Themen
Amazon Preisbeobachung mit Preisalarm

zum Seitenanfang zum Seitenende Profil || Suche
059
09.12.2002, 11:22
K-Putt



Zitat:
King of Darkness postete

unsigned long Länge;

Ich bin zwar kein Profi, aber seit wann funktionieren Umlaute in Variablennamen?

--

Rambo Engineer @ Drippy's 2fort - finest TFC 1.5 || Bild Upload || The world's most advanced open source database

zum Seitenanfang zum Seitenende Profil || Suche
060
10.12.2002, 08:53
King of Darkness



das stimmt das is ja auch aus dem kopf, natürlich habe ich im richtigen code laenge stehen ;)
aber trotzdem macht das proggie den speicher nicht frei, erst wenn ich es schliesse

--

Coding Center --- Tutorials über Programmierung und andere Themen
Amazon Preisbeobachung mit Preisalarm

zum Seitenanfang zum Seitenende Profil || Suche
061
10.12.2002, 10:52
Kriz



Hm, hm, hm...

Ich schreib dir mal ne Klassendefinition auf für eine doppelt verkettete Liste. Sie ist nicht-virtuell, sollte daher nicht unbedingt abgeleitet und überladen und nachher mit wilden Objektzeigern attackiert werden. Durch die nicht-virtuelle Definition erhöht sich die Geschwindigkeit der Klasse (zum Nachteil der Ableitbarkeit und dem restlichen OOP Gelümmel). Außerdem verzichtet sie auf einen Kopierkonstruktor. Die Daten werden als void-Zeiger gespeichert. Es ist nur darauf zu achten, daß beim "getten" des Inhalts richtig zurückgecastet wird. Das mußt du also schon selber übernehmen!

Quellcode:class CDoubleLinkedList
{
    CDoubleLinkedList *m_pListBase; // Basiszeiger pro Liste
    CDoubleLinkedList *m_pListActual; // Zeiger auf das aktuelle Element pro Liste
    CDoubleLinkedList *m_pNextElement; // Zeiger auf das nächste Element
    CDoubleLinkedList *m_pPreviousElement; // Zeiger auf das vorherige Element
    unsigned int m_uiListSize; // Listengröße
    void* m_pContent; // Zeiger auf den Inhalt des Elements
public:
    CDoubleLinkedList();
    ~CDoubleLinkedList();
public:
    int Add(void* pContent); // Neues Element hinten anhängen
    int Insert(void* pContent); // Neues Element nach dem aktuellen Element einfügen
    int Remove(void); // Aktuelles Element löschen und nachfolgendes Element als aktuelles Element deklarieren
    bool IsEmpty(void); // Prüfen, ob die Liste leer ist
    int ToNext(void); // Zum nächsten Element gehen
    int ToPrevious(void); // Zum vorherigen Element gehen
    int ToBegin(void); // Zum Anfang der Liste gehen
    int ToEnd(void); // Zum Ende der Liste gehen
    int Clear(void); // Liste komplett löschen und als "empty" deklarieren
    unsigned int GetSize(void); // Anzahl der Elemente zurückgeben
    int GetContent(void* pReceiver); // Inhalt des aktuellen Elements holen
};

Hm, um dir jetzt die konkrete Arbeitsweise aller Methoden untereinander zu erklären, müßte DarthPaul erstmal die maximale Zeichenanzahl pro Post drastisch erhöhen *ggg*. Aber laß mal deine Kreativität spielen (ich weiß, daß dieser Satz gerade SEHR entmutigend war, aber nur durch Try-and-error kommt man ordentlich weiter).

Dieser Ansatz ist nur einer von vielen in C++!!!

Cu

--

K:R-I)Z++
"CSS ist cascading style sheets. Und nicht so'n Ranzspiel." - dp
In memory of Voice († 2005/03/30)


Dieser Beitrag wurde am 10.12.2002 um 10:52 von Kriz bearbeitet.
zum Seitenanfang zum Seitenende Profil || Suche
062
10.12.2002, 10:59
King of Darkness



ja das is mir alles klar und du bringst auch ein paar nette idee, aber ich denke das löst nicht mein problem :(, ich kann ja mal morgen den code posten (ca 250 bis 300 zeilen) aber vorher schau ich noch mal ganz genau mit debug durch ;)

und wenn ich ihn poste kann ich dann ja gleich noch ein anderes weniger problematisches problem posten ;)

--

Coding Center --- Tutorials über Programmierung und andere Themen
Amazon Preisbeobachung mit Preisalarm

zum Seitenanfang zum Seitenende Profil || Suche
063
10.12.2002, 15:10
Tron



Zitat:
Kriz postete
Die Daten werden als void-Zeiger gespeichert. Es ist nur darauf zu achten, daß beim "getten" des Inhalts richtig zurückgecastet wird. Das mußt du also schon selber übernehmen!

kriz, ich bin _entsetzt_!
*husthust* templates *husthust*

und vom aufbau her sollten sich die listenelemente auch nicht selbst verwalten...

--

'KEINE PANIK' - aus der Triologie in fuenf Baenden von Douglas Adams

'FÜR DEINN FERD' - aus 'Gevatter Tod' von Terry Pratchett

zum Seitenanfang zum Seitenende Profil || Suche
064
11.12.2002, 08:43
Kriz



I know. Aber er wollte ja was über eine Klasse wissen...

Nun ja, man kann eine Liste entweder als Inhalt + Manager implementieren oder als Inhalt und als separaten Manager. Ich bevorzuge die erste Variante, weil es irgendwie herausfordender ist, hehehe!

=)

--

K:R-I)Z++
"CSS ist cascading style sheets. Und nicht so'n Ranzspiel." - dp
In memory of Voice († 2005/03/30)


Dieser Beitrag wurde am 11.12.2002 um 08:44 von Kriz bearbeitet.
zum Seitenanfang zum Seitenende Profil || Suche
065
11.12.2002, 09:21
King of Darkness



is doch denke ich mal nich das problem kommt drauf an was der manager machen soll ;)
aber wie versprochen mein code:
erstmal die header:
Quellcode:
#ifndef LISTE_H
#define LISTE_H
#include <stdlib.h>
#endif

///Objektklasse///
class objekt
{
public:

        char *zeichen;

    objekt()
    {
        zeichen = new char;
    }
    ~objekt()
    {
        free(zeichen);
    }

};

///listenklasse///
class liste
{

    public:
    liste *pNext;                                //zeiger auf nächstes objekt in der liste
    liste *pBefore;                                //zeiger auf vorhergehendes objekt in der liste

    objekt *pDaten;                                //daten
    bool *pAktiv;                                //status
    unsigned long *Index;                        //indexnummer

    liste()
    {
        pDaten = new objekt;    
        pAktiv = new bool;
        pNext = NULL;
        pBefore = NULL;
        Index = new unsigned long;
    };                                    
    ~liste()
    {
        free(pDaten);
        free(pAktiv);
        free(pNext);
        free(pBefore);
        free(Index);
    };                                    


private:
};

///objektelistenklasse///
class objektliste
{
public:
    liste *pErstes;                                //erstes objekt in der liste
    liste *pLetztes;                            //letztes objekt der liste
    liste *pObjekt;                                //aktuelles objekt auf das gezeigt wird
    liste *pNext;                                //tempzeiger
    liste *pBefore;                                //tempzeiger
    liste *pTemp;                                //tempzeiger

    unsigned long Laenge;                        //aktuelle länge der liste


    unsigned long x_counter;                    //zähler
    unsigned long y_counter;                    //zähler

    objektliste()
    {
        pErstes = new liste;        
        pObjekt = new liste;        
        pLetztes = new liste;
        pNext = 0;
        pBefore = 0;
        pTemp = 0;
        Laenge = 0;

    }

    ~objektliste()
    {
        Destroy();
    }
    
    int SetObjekt( unsigned long *pIndex);                        //setzt pObjekt auf das objekt mit dem entschprechenden index und gibt true zurück
    int AddObjekt(objekt *Objekt);                                //fügt ein objekt der liste hinzu, und gibt true zurück
    int InsertObjekt(objekt *Objekt, unsigned long *pIndex);    //fügt ein objekt vor dem objekt mit dem entsprechenden Index ein
    int SetNext();                                                //Setzt pObjekt auf nächstes objekt
    int SetBefore();                                            //Setzt pObjekt auf vorhergehendes objekt
    int SetToBegin();                                            //Setzt pObjekt auf Erstes objekt
    int SetToEnd();                                                //Setzt pObjekt auf Letztes objekt

    void Destroy();                                                //gibt speicher zurück von den objekten die leer sind


private:
};


///////////////////jetz die cpp
Quellcode:
#include "verkettete_liste.h"

int objektliste::AddObjekt(objekt *Objekt)
{
    if(Laenge == 0)
    {
        pObjekt = new liste;

        *pObjekt->Index = Laenge;
        *pObjekt->pAktiv = true;
        *(pObjekt->pDaten->zeichen) = *(Objekt->zeichen);

        pErstes = pObjekt;
        pLetztes = pObjekt;

        Laenge++;
        return true;
    }
    else if(!pErstes->pNext)
    {
        pObjekt = new liste;        

        *pObjekt->Index = Laenge;
        *pObjekt->pAktiv = true;
        *(pObjekt->pDaten->zeichen) = *(Objekt->zeichen);

        pObjekt->pBefore = pErstes;
        pErstes->pNext = pObjekt;
        pLetztes = pObjekt;

        Laenge++;
        return true;
    }
    else if(Laenge > 0)
    {
        pObjekt = new liste;        

        *pObjekt->Index = Laenge;
        *pObjekt->pAktiv = true;
        *(pObjekt->pDaten->zeichen) = *(Objekt->zeichen);


        pObjekt->pBefore = pLetztes;
        pLetztes->pNext = pObjekt;
        pLetztes = new liste;
        pLetztes = pObjekt;
        pLetztes->pNext = NULL;

        Laenge++;
        return true;
    }

    return false;
}

int objektliste::InsertObjekt(objekt *Objekt, unsigned long *pIndex)
{
    if(Objekt != 0)
    {
        if(SetObjekt(pIndex))
        {
            pTemp = new liste;
            pTemp->pNext = pObjekt;
            pObjekt = pObjekt->pBefore;
            pTemp->pBefore = pObjekt;
            pObjekt->pNext = pTemp;
            pObjekt = pTemp->pNext;
            pObjekt->pBefore = pTemp;
            
            *pTemp->pDaten->zeichen = *Objekt->zeichen;
            *pTemp->pAktiv = true;
            *pTemp->Index = Laenge;
            Laenge++;
            return true;
        }    
    }
    return false;
}

int objektliste::SetNext()
{
    if(pObjekt->pNext)
    {
        pObjekt = pObjekt->pNext;
        return true;
    }
    else
    {
        return false;
    }
}

int objektliste::SetBefore()
{
    if(pObjekt->pBefore)
    {
        pObjekt = pObjekt->pBefore;
        return true;
    }
    else
    {
        return false;
    }
}

int objektliste::SetToBegin()
{
    if(pErstes)
    {
        pObjekt = pErstes;;
        return true;
    }
    else
    {
        return false;
    }
}

int objektliste::SetToEnd()
{
    if(pLetztes)
    {
        pObjekt = pLetztes;
        return true;
    }
    else
    {
        return false;
    }
}

void objektliste::Destroy()
{
    if(pLetztes)
    {
        pObjekt = pLetztes;
    }
    else
    {
        return;
    }
    for(;;)
    {        
        if(!pObjekt)
        {
            pLetztes = 0;
            pErstes = 0;
            break;
        }
        else
        {
            pNext = pObjekt->pNext;
            pBefore = pObjekt->pBefore;
            free(pObjekt);        
            if(pNext)
            {
                pNext->pBefore = pBefore;
            }
            if(pBefore)
            {
                pBefore->pNext = pNext;
            }
            Laenge--;
            pLetztes = pBefore;            
            pObjekt = pBefore;
        }
    }
}

int objektliste::SetObjekt(unsigned long *pIndex)
{
    if(pErstes)
    {
        pObjekt = pErstes;
    }
    if(!pObjekt)    
    {
    }
    else
    {
        for(;;)
        {
            if(!pObjekt)    
            {
                break;
            }
            if(*pObjekt->Index == *pIndex)
            {
                return true;    
            }
            else
            {
                pObjekt = pObjekt->pNext;
            }
        }
    }
    return false;
}

--

Coding Center --- Tutorials über Programmierung und andere Themen
Amazon Preisbeobachung mit Preisalarm


Dieser Beitrag wurde am 11.12.2002 um 09:25 von King of Darkness bearbeitet.
zum Seitenanfang zum Seitenende Profil || Suche
066
11.12.2002, 09:25
King of Darkness



///////////////////////und jetz die main mit der ich das ganze teste
Quellcode:
#include "verkettete_liste.h"

#include <iostream>
using namespace std;

int main()
{    
    char text[] = "ABCDEFGHIJK";
    unsigned long *y = new unsigned long;
    unsigned long temp;
    int eingabe;
    unsigned long *zahl = new unsigned long;
        
    objekt *Objekt = new objekt;

    objektliste *pObjektliste = new objektliste;

    temp = strlen(text);

//    for(int z = 0; z != 10000; z++)
//    {
        for(int x=0; x!=temp; x++)
            {
                *Objekt->zeichen = text[x];
                pObjektliste->AddObjekt(Objekt);
            }
//    }


    for(;;)        //mainloop
    {    
        cout << "------------------------------------------------------" <<endl;
        cout << "anzahl der objekte : " << pObjektliste->Laenge << endl;
        cout << "------------------------------------------------------" <<endl << endl;
        cout << "1 objekt hinzufuegen" << endl;
        cout << "2 speicher frei geben" << endl;
        cout << "3 alles ausgeben" << endl;
        cout << "4 viele objekte hinzufügen" << endl;
        cout << "5 zeichen einfügen" << endl;

        cin >> eingabe;

        cout << endl;

        switch(eingabe)
        {
        case 1:
            {
                cout << "EIN zeichen eingeben" << endl;
                cin >> Objekt->zeichen;
                pObjektliste->AddObjekt( Objekt );
                break;
            }
        case 2:
            {
                pObjektliste->Destroy();
                break;
            }
        case 3:
            {/*                
                for(*y=0;;*y = *y+1)
                {
                    if(!pObjektliste->SetObjekt(y))
                    {
                        break;
                    }
                    cout << *(pObjektliste->pObjekt->Index) << endl;
                    
                }
                cout << endl;
            */
                if(pObjektliste->SetToBegin())
                for(;;)
                {
                    cout << *pObjektliste->pObjekt->Index << endl;
                    if(!pObjektliste->SetNext())
                    {
                        break;
                    }
                }

                break;
            }
        case 4:
            {
                for(int z = 0; z != 10000; z++)
                {
                    for(int x=0; x!=temp; x++)
                    {
                        *Objekt->zeichen = text[x];
                        pObjektliste->AddObjekt(Objekt);
                    }
                }
                break;
            }
        case 5:
            {
                
                cout << "EIN zeichen eingeben" << endl;
                cin >> Objekt->zeichen;
                cout << "vor welches objekt soll es gesetzt werden ?" << endl;
                cin >> *zahl;
                if(!pObjektliste->InsertObjekt(Objekt, zahl))
                {
                    cout << "wahhhhhh fehler" << endl;
                }
                break;
            }

        default:
            {
               break;
            }
        }
    }
    return 0;

}

so und jezt nich böse sein aber ich will ne konkrete antwort warum der den speicher nicht frei gibt wenn ich die funtion destroy aufrufe, und vieleicht noch ein paar tips,

sorry wenn das jetz ein bischen viel war

--

Coding Center --- Tutorials über Programmierung und andere Themen
Amazon Preisbeobachung mit Preisalarm

zum Seitenanfang zum Seitenende Profil || Suche
067
11.12.2002, 16:59
dp
Administrator


das forum hat nicht umsonst ne zeichenbegrenzung, das nächste mal bitte linken..

--

zum Seitenanfang zum Seitenende Profil || Suche
068
11.12.2002, 17:15
Tron



Quellcode:public:

        char *zeichen;

    objekt()
    {
        zeichen = new char;
    }
    ~objekt()
    {
        free(zeichen);
    }

};

ARGH!
NIEMALS mit new alloziieren und dann mit free freigeben! niemals, niemals, niemals!

new <-> delete
new[] <-> delete[]
malloc <-> free

_NIEMALS_ mischen

falls dir der unterschied zwischen den 3 paaren nicht bekannt ist, fehlen dir wichtige grundlagen bzgl. dynamischer speicheralloziierung!

Quellcode:liste *pTemp;                                //tempzeiger
wozu ist das denn?

Quellcode:Index = new unsigned long;
unsigned long *y = new unsigned long;
unsigned long *zahl = new unsigned long;

und das?

Quellcode:                for(;;)
                {
                    cout << *pObjektliste->pObjekt->Index << endl;
                    if(!pObjektliste->SetNext())
                    {
                        break;
                    }
                }

extrem haesslich! hier ist eine do schleife wesentlich besser geeignet.

Quellcode:for(int z = 0; z != 10000; z++)
++ immer praefix verwenden!

Quellcode:int objektliste::AddObjekt(objekt *Objekt)
{
    if(Laenge == 0)
    {
        pObjekt = new liste;

        *pObjekt->Index = Laenge;
        *pObjekt->pAktiv = true;
        *(pObjekt->pDaten->zeichen) = *(Objekt->zeichen);

        pErstes = pObjekt;
        pLetztes = pObjekt;

        Laenge++;
        return true;
    }

urgs! wenn eine funktion true/false zurueckgibt, dann soll sie auch als bool deklariert werden.

die implementierungen von AddObjekt und InsertObjekt sind mir ziemlich schleierhaft, scheinen mir auch fehlerbehaftet zu sein, aber so genau hab ich die mir noch net angesehen.

--

'KEINE PANIK' - aus der Triologie in fuenf Baenden von Douglas Adams

'FÜR DEINN FERD' - aus 'Gevatter Tod' von Terry Pratchett

zum Seitenanfang zum Seitenende Profil || Suche
069
12.12.2002, 11:32
King of Darkness



mhhh also gut ok das mit dem alloc werde ich ändern
aber das möchte ich genau wissen, wieso nicht mischen ?

liste *pTemp;
das ist für insert objekt, ok könnte ich auch in der func machen.

das mit der do schleife, kann ja dort egal sein da das ja ehn nur ein sinniges testproggi ist, in dem ich die liste teste, aber wenn ich die richtig nutze kann ich das ja mit do machen

und wieso immer perfix und nich suffix is das nich egal, ok was das letzte objekt betrifft mhhh ?

und was ist schleierhaft ? fehlerhaft kann es nich sein da es geht, es gibt zwar fehler die nich auffallen aber ich bin der meinung das es geht, vieleicht nicht die beste lösung, aber es geht

--

Coding Center --- Tutorials über Programmierung und andere Themen
Amazon Preisbeobachung mit Preisalarm

zum Seitenanfang zum Seitenende Profil || Suche
070
12.12.2002, 14:49
Prefect



Also, mit new reservierte Speicherblöcke darf man einfach deswegen nicht mit free() freigeben, weil das laut dem Standard nicht geht. Klar - in manchen Implementationen geht's ohne Probleme, aber new und malloc() holen sich ihren Speicher in anderen Implementationen vielleicht von zwei verschiedenen Heaps. Und wenn du dann mit delete ein per malloc() reservierten Speicherblock freigeben willst kriegst du Ärger, weil delete den Speicherblock eben im eigenen Heap erwartet.
new[] (also der Array-Allocator) fügt insgeheim vor den Speicherblock die Anzahl der reservierten Elemente ein, damit delete[] hinterher weiß, für wieviele Elemente der Destruktor aufgerufen werden muß. Wenn du einen per new[] reservierten Speicherblock mit delete freigeben willst, dann übergibst du also einen Pointer, der nicht auf den Anfang eines Speicherblocks zeigt, und sowas mögen Heapmanager gar nicht (d.h. sie crashen früher oder später).
Von den ganzen Unterschieden bezüglich Aufrufen von Konstruktoren und Destruktoren wollen wir erst gar nicht reden...

liste *pTemp;
Diese Variable gehört einfach nicht zu dem Objekt. Du mußt bei der Konstruktion von Objekten genau analysieren, was für ein Objekt du eigentlich implementierst. In diesem Fall implementierst du eine Liste. Eine Liste besteht eben aus einer Liste von Objekten, und _nur_ aus einer Liste von Objekten.
Ein pTemp-Zeiger gehört sicherlich nicht zur gängigen Vorstellung einer Liste. Allgemein gehören temp-Variablen _nie_ in eine Klassendefinition rein, weil sie _nie_ etwas mit dem momentanen Zustand des Objektes zu tun haben.

Das mit Postfix vs. Prefix-In/Dekrement kann ich ehrlich gesagt auch nicht nachvollziehen. Gibt's da eine rationale Begründung?

Wenn es Fehler gibt, die nicht auffallen, dann ist das Programm per Definition fehlerhaft. Wenn du solche Fehler durchgehen läßt mit der Begründung, daß das Programm ja im Moment funktioniert, wird das relativ schnell übel enden. Irgendwann werden diese Fehler nämlich mit einem neu eingebauten Programmteil auf eine unvorhergesehende Weise interagieren und du wirst die Freude haben, absolut unverständliche Abstürze debuggen zu dürfen.

BTW: char* pChar = new char;
Code in dieser Art ist absolut sinnlos. Ich hoffe ich muß nicht erklären warum.

cu,
Prefect

--

Widelands - Gemütliche Aufbaustrategie, Free Software
Noch ein Blog - Lerne, wie die Welt wirklich ist, aber vergiss niemals, wie sie sein sollte.

zum Seitenanfang zum Seitenende Profil || Suche
071
12.12.2002, 16:46
Tron



Zitat:
Das mit Postfix vs. Prefix-In/Dekrement kann ich ehrlich gesagt auch nicht nachvollziehen. Gibt's da eine rationale Begründung?

postfix ist, wenn der optimierer nicht schlau ist nunmal langsamer (hier ist das zwar voellig egal und heutige compiler sind so schlau, aber es geht hier um's prinzip!)
spaetestens wenn i kein int ist sondern ein iterator (stichwort stl) kann der optimierer nichts mehr drehen.

objekte, die einen konstruktor und/oder destruktor haben, der nicht leer ist _niemals_ mit malloc/free handhaben, da diese den konstruktor/destruktor nicht aufrufen! und das mit den verschiedenen heaps sagte prefect ja schon.

bezueglich AddObjekt:
[code]if(Laenge == 0)
{}
else
if(!pErstes->pNext)
{}
else
if(Laenge > 0)
{}

das letzte if ist _immer_ wahr, falls es erreicht wird. (ergibt sich aus dem ersten if und daraus, dass Laenge immer >= 0 ist)
also stimmt da was an deinen ueberlegungen nicht! deswegen habe ich einfach mal daraus geschlossen, dass da was falsch ist, wie gesagt, hab' mir nicht die muehe gemacht, das genau unter die lupe zu nehmen

bezueglich InsertObjekt:
falls man per InsertObjekt an das ende der liste anfuegt (kann ja vorkommen), dann wird dir die methode um die ohren fliegen, da es kein naechstes objekt gibt, dessen vorgaenger-zeiger man setzen koennte.
analog fuer den anfang der liste.
halt! durch die implementierung deiner SetObjekt-methode (die auch einige merkwuerdigkeiten enthaelt, z.b. ein redundantes if und eine endlosschleife)
kann das einfuegeproblem nur am anfang der liste auftreten

der konstruktor deiner klasse objektliste scheint auch fehler zu enthalten, du erzeugst dort 3 liste-objekte als erstes, aktuelles und letztes, die nichts voneinander wissen, das stinkt nach potentiellen verwaisten objekten.

--

'KEINE PANIK' - aus der Triologie in fuenf Baenden von Douglas Adams

'FÜR DEINN FERD' - aus 'Gevatter Tod' von Terry Pratchett

zum Seitenanfang zum Seitenende Profil || Suche
072
13.12.2002, 08:51
King of Darkness



wahhh danke ;)

zum letzten: wenn du ein objekt an das ende anfügen willst nimmst du addobjekt ansonsten insert ;)
das mit if(laenge > 0) mhhh ok hast recht ;), das stammt aber noch aus einer andren zeit ;) als ich auch mit leeren objekten arbeiten wollte

ich habe die free()´s duch delete´s ersetzt und der speicher wird besser behandelt, aber eben nur besser und nich gut- das problem ist immer noch das wenn ich den speicher frei gebe es mir nicht angezeigt wird (im taskmanager von win2k) dor steig der speicher fast immer, wenn ich allerdings 330000 objekte in liste lade und die dann wieder raus kicke bleibt die ramverwendung gleich hoch, wenn ich aber wieder 110000 objekte hinzufüge reserviert er keinen neuen speicher, bei den nächsten 110000 objekte etwas speicher und dann bei den nächsten 110000, das habe ich mal so lange betrieben bis mein rechner überlastet war am ende hatte ich 770000 objekte in der liste und habe den speicher wieder frei gegeben, ne zeit gewartet, und der ram blieb immernoch bei rund 700 MB, programm beendet dann dung er wieder runter auf rund 90 MB (etwas viel ich weiss), wo ist allso sein problem ? wieso gibt er den speicher nicht an windoof zurück oder is das win zu blöd dazu das zu erkennen das da wieder speicher frei geben ist?

oder is das proggie fehlerhaft (ihr werde sicher sagen proggi fehler)

--

Coding Center --- Tutorials über Programmierung und andere Themen
Amazon Preisbeobachung mit Preisalarm

zum Seitenanfang zum Seitenende Profil || Suche
073
13.12.2002, 14:34
Prefect



Ah ja, das mit Prefix/Postfix stimmt natürlich. Bei Postfix muß der Compiler im Prinzip ein neues Objekt erstellen um den alten Zustand zurückgeben zu können, bei Prefix nicht. Solange alle Funktionen inline gehandelt wird dürfte es natürlich keinen Unterschied machen, aber das Prinzip zählt :)

cu,
Prefect

--

Widelands - Gemütliche Aufbaustrategie, Free Software
Noch ein Blog - Lerne, wie die Welt wirklich ist, aber vergiss niemals, wie sie sein sollte.

zum Seitenanfang zum Seitenende Profil || Suche
074
13.12.2002, 16:46
Mazze



Jepp, im Stroustrup steht, dass man z.B.
y = ++x ist äquivalent zu y = (x+=1)
y = x++ ist äquivalent zu y = (t=x, x+=1, t)
Man sieht, dass x++ etwas komplizierter bei der Auflösung ist.

cu
Matze

--

BattleTech-MOD:
http://bthl.unitedgaming.net/

zum Seitenanfang zum Seitenende Profil || Suche