Mit new erstellten Zeiger in vector pushen?



  • Möchte boost vorerst nicht verwenden.

    rüdiger schrieb:

    du musst dich um die Freigabe des Speichers kümmern.

    Wie mache ich das?

    MfG



  • Wenn du Speicher mit new anforderst, gibst Du ihn mit delete wieder frei. Bei new ... [ ... ] mit delete[ ].

    zb:

    int main( ) {
    
        int *number = new int;
    
        // ...
    
        delete number;
    
        // aber:
    
        int *numbers = new int[ 10 ];
    
        // ...
    
        delete [ ] numbers;
    }
    

    Greetz, Swordfish



  • Wenn das vertices auf Grafik deutet, dann solltest du vorher erst mal die Grundlagen von C++ lernen.



  • Das heißt, ich müsste dann für jedes Element "delete [] mapList[x].index;" schreiben?

    MfG



  • ma ... du musst halt wenn bsw dein std::vector in einer Klasse ist, im Destruktor den Kompletten Vektor durchgehen. Jedes Item erstmal selbst löschen ... dann die clear Funktion von der std::vector Klasse aufrufen ...



  • (D)Evil schrieb:

    [...] dann die clear Funktion von der std::vector Klasse aufrufen ...

    Ist aber nicht unbedingt nötig 😉 .

    Also @ceplusplus, hier mal ein Beispiel:

    #include <vector>
    
    class CFoo
    {
      // ...
    };
    
    typedef std::vector<CFoo*> CFooVector;
    
    // ...
    
    CFooVector cFoos;
    CFoo* pNew;
    
    // mit 10 Elementen füllen:
    for(int i = 1; i <= 10; i++)
    {
      pNew = new CFoo(/*evtl. Parameter*/);
      cFoos.push_back(pNew);
    }
    
    // ... Damit arbeiten ...
    
    // Den Speicher der Elemetne auf dem Heap wieder freigeben, der Rest sollte vom std::vector-Destruktor erledigt werden:
    for(int i = 0; i < cFoos.size(); i++)
       delete cFoos[i];
    


  • Danke! Es sieht aber so aus:

    struct Map
    {
        // ...
    	struct Vertex
    	{
    		float x, y, z;
    	};
    
    	Vertex* vertex;
        // ...
    };
    
    // ...
    Map map;
    map.vertex = new Map::Vertex[24];
    // ...
    
    // ...
    std::vector<Map> mapList;
    // ...
    mapList.push_back(map);
    // ...
    

    Also muss ich dann

    delete [] mapList[x].vertex;

    schreiben?

    MfG



  • Mach lieber so:

    struct Map
    {
        // ...
        Map( size_t size )
        {
            vertex = new Vertex[size];
        }
        ~Map()
        {
            delete[] vertex;
        }        
        struct Vertex
        {
            float x, y, z;
        };
        Vertex* vertex;
        // ...
    };
    

    Dann kümmert sich map selbst um den Speicher und du kannst den vector ganz normal benutzen.



  • Interessant. Danke.

    MfG



  • Google mal nach RAII ( Resource Acquisition Is Initialization )



  • THX 1138 schrieb:

    Mach lieber so:

    struct Map
    {
        // ...
        Map( size_t size )
        {
            vertex = new Vertex[size];
        }
        ~Map()
        {
            delete[] vertex;
        }        
        struct Vertex
        {
            float x, y, z;
        };
        Vertex* vertex;
        // ...
    };
    

    Dann kümmert sich map selbst um den Speicher und du kannst den vector ganz normal benutzen.

    Als erster Schritt schon mal 'ne gute Sache. Sauber wird es, wenn man die sogenannte 'Regel der drei' befolgt, die da lautet: "Falls ein nicht trivialer Destruktor (oder Zuweisung-Operator oder Kopier-Konstruktor) in der Klasse auftaucht, so muss man auch die anderen beiden implementieren."

    Für den Anfang würde es auch reichen, diese einfach 'lahm zu legen' - inden man sie private macht.

    struct Map
    {
        // ...
        explicit Map( size_t size ) // explicit verhindert implizite Konvertierung
            : vertex( new Vertex[size] ) // Initialisierungslisten verwenden
        {}
        ~Map()
        {
            delete[] vertex;
        }        
        struct Vertex
        {
            float x, y, z;
        };
    private:  // 'vertex' bessser auch private machen
        Vertex* vertex;
        // ...
    private:
        Map( const Map& );
        Map& operator=( const Map& );
    };
    

    .. falls Dein Code anschließend nicht mehr compiliert, hat Dich diese Konstruktion vor einem bösen Laufzeitfehler bewart.

    Gruß
    Werner



  • "Falls ein nicht trivialer Destruktor (oder Zuweisung-Operator oder Kopier-Konstruktor) in der Klasse auftaucht, so muss man auch die anderen beiden implementieren."

    Verstehe ich nicht.

    MfG



  • Eventuell meint er Konstruktor



  • Nein, tut er glaub ich nicht 😉



  • Knuddlbaer schrieb:

    Eventuell meint er Konstruktor

    Nein, er meint Destruktor.
    Ein Destruktor gilt als nicht trivial, wenn er z.B. eine delete enthält oder auch einen anderen Aufruf, der eine Ressource gleich welcher Art wieder freigibt.

    Beim (automatischen) Kopieren eines Objekt mit Zeiger (hier vertex) wird natürlich nur der Zeiger kopiert, wird jetzt eines der beiden Objekte, also die Kopie oder das Original gelöscht, so wird sein Konstruktor aufgerufen und die Ressource freigegeben. Das andere Objekt läuft dann mit einem Zeiger herum der nicht mehr gültig ist und spätestens beim Löschen des Zweiten Objekts kracht es dann.

    Mehr dazu wenn man 'rule of three c++' bei google eingibt. Unter anderen ist es hier ganz gut beschrieben. In deutsch gibt's das auch hier

    Gruß
    Werner



  • ceplusplus schrieb:

    struct Map
    {
        // ...
    	struct Vertex
    	{
    		float x, y, z;
    	};
    
    	Vertex* vertex;
        // ...
    };
    
    // ...
    Map map;
    map.vertex = new Map::Vertex[24];
    // ...
    
    // ...
    std::vector<Map> mapList;
    // ...
    mapList.push_back(map);
    // ...
    

    Allerdings schreibe ich nach push_back():

    delete [] map.vertex;

    Trotzdem arbeite ich dann wie gewohnt mit dem Objekt im Vektor.

    MfG



  • ceplusplus schrieb:

    ceplusplus schrieb:

    std::vector<Map> mapList;
    // ...
    mapList.push_back(map);
    // ...
    

    Allerdings schreibe ich nach push_back():

    delete [] map.vertex;

    Trotzdem arbeite ich dann wie gewohnt mit dem Objekt im Vektor.

    Ja, da haben wir es ja schon 🕶

    Dringender Tipp: Füge einen Kopier- und einen Zuweisungs-Operator für Map hinzu, in Deinem Fall public und wenn Du nicht weist wie das geht, so frag' noch mal nach. Ich gehe jetzt Fernsehen schauen - aber die anderen können Dir auch helfen.

    Gruß
    Werner



  • Kopierkonstruktor ok für meinen Fall. Zuweisungsoperator ist daweil nicht dringend nötig?!

    Aber warum funktioniert es eigentlich auch ohne dem? Der Zeiger des Objekts zeigt auf ein array. Wenn man nun push_back() aufruft, wird das Objekt also kopiert... und somit auch der Zeiger. Der zeigt dann eigentlich auf die alte Adresse, die aber von delete schon wieder freigegeben wurde.

    Warum sind die Daten dann immer noch da?

    MfG



  • ceplusplus schrieb:

    Warum sind die Daten dann immer noch da?

    wahrscheinlich weil bis dahin niemand in den Speicher hineingeschrieben hat. Aber was nicht ist, kann noch kommen. Ist auch eine Frage Deiner verwendeten Umgebung. Das VisualStudio z.B. überschreibt freigegebenen Speicher im Debug-Mode und es erkennt zweimal freigegebenen Speicher als Fehler; das scheint bei Dir nicht der Fall zu sein.

    Wenn ich's so recht überlege gäbe es für Dich eine sehr einfache Lösung. Nutze einfach einen std::vector um die Vertex zu speichern.

    struct Map
    {
        struct Vertex
        {
            float x, y, z;
        };
    
        explicit Map( size_t size )
            : vertex( size ) // legt 'size' Vertex-Objekte an
        {}
    
        std::vector< Vertex > vertex;
    };
    

    und das war's schon. Destruktor, Kopie-Konstruktor und Zuweisung-Operator von Map macht alles der vector und der Compiler - und Du musst Dich um nichts mehr kümmern. Ansonsten sollte sich Dein Code dadurch nicht wesentlich verändern - wenn überhaupt, so wird er einfacher.

    Gruß
    Werner



  • Okay danke. Wenn das performant ist. Ist ein Maploader, da wird schon mal ordentlich "gepusht".

    MfG

    EDIT:
    Wozu " : vertex( size ) // legt 'size' Vertex-Objekte an " ? Verstehe ich nicht. Der std::vector wird doch die Vertexobjekte speichern.


Anmelden zum Antworten