Structs und listen



  • Ich nutze einfach nochmal hier das Thema.

    ich habe jetzt mal weiter an dem Code mich versucht und wollte jetzt die Elemente aus der Liste löschen und danach die Liste an sich löschen.
    Ich möchte erst die Elemente aus der List mit delete[] entfernen, da diese mit new Operator erzeugt wurden und dann am Ende die Liste mit list.clear() entfernen.

    nun wirft er mir aber folgenden Fehler:

    // MEMBER FUNCTIONS FOR _Container_base12
    inline void _Container_base12::_Orphan_all() noexcept {
    #if _ITERATOR_DEBUG_LEVEL == 2
        if (_Myproxy) { // proxy allocated, drain it
            _Lockit _Lock(_LOCK_DEBUG);
    
            for (auto _Pnext = &_Myproxy->_Myfirstiter; *_Pnext; *_Pnext = (*_Pnext)->_Mynextiter) {
                (*_Pnext)->_Myproxy = nullptr;
            }
    
            _Myproxy->_Myfirstiter = nullptr;
        }
    #endif // _ITERATOR_DEBUG_LEVEL == 2
    

    Anhand dieser Meldung gehe ich mal davon aus, dass es ein Problem mit einem nullptr existiert^^

    hier der Code mit dem ich löschen möchte:

    void Remove(SDataBase* _pTownData)
    {
    	
    	string erase;
    
    	system("cls");
    
    	cout << "Geben Sie die Stadt ein, nach der Sie suchen l\224schen m\224chten: ";
    	cin >> erase;
    
    	for (SCity* eraseList : _pTownData->cityList)
    	{
    
    		if (eraseList->name == erase)
    		{
    
    			_pTownData->cityList.remove(eraseList);
    
    		}
    
    
    	}
    
    	_pTownData->counter = _pTownData->counter - 1;
    
    }
    

    und der hier:

    void Finalize(SDataBase* _pTownData)
    {
    
    
    	for (SCity* deleteCity : _pTownData->cityList)
    	{
    
    		delete[] deleteCity;
    
    	}
    
    
    
    	_pTownData->cityList.clear();
    
    }
    

    Und so werden Elemente ich die Liste gepackt:

    void Add(SDataBase* _pTownData)
    {
    
    	SCity* exampleCity = CreateCity();
    
    	_pTownData->cityList.push_back(exampleCity);
    
    	_pTownData->counter = _pTownData->counter + 1;
    
    	cout << "Es wurde eine Stadt zur Database hinzugef\201gt." << endl;
    }
    
    

    Das Programm läuft, außer wenn die Routinen Finalize und Remove verwendet werden, dann kommt immer der oben gezeigt Fehler 🙂

    Ich danke schon mal wieder für eure Hilfe 🙂



  • @Avartos sagte in Structs und listen:

    delete[] deleteCity;

    Und das ist ein Array (d.h. mit new[] allokiert)?



  • Nein ein Array verwende ich ja in dem Sinne nicht.

    SCity* CreateCity()
    {
    
    	SCity* egTown = new SCity();
    
    	cout << endl;
    	cout << "Geben Sie einen Namen f\201r die Stadt ein: ";
    	cin >> egTown->name;
    	cout << endl;
    	cout << "Nun geben Sie das Bundesland ein: ";
    	cin >> egTown->state;
    	cout << endl;
    	cout << "Als letztes geben Sie die Zahl der Einwohner ein: ";
    	cin >> egTown->population;
    	cout << endl;
    
    	return egTown; 
    
    }
    

    so wird das Element für die Liste erzeugt



  • @Avartos Und warum löscht du es als Array?



  • weil delete[] ja dafür da ist Sachen aus dem Speicher zu löschen die mit new erzeugt wurden? Das sagt mir jedes Buch 😃 Erzeugst du was mit new, dann lösche es auch wieder mit delete[]



  • @Avartos sagte in Structs und listen:

    weil delete[] ja dafür da ist Sachen aus dem Speicher zu löschen die mit new erzeugt wurden? Das sagt mir jedes Buch Erzeugst du was mit new, dann lösche es auch wieder mit delete[]

    Nein, das sagt nicht jedes Buch. Jedes Buch, das das sagt, solltest du in den Müll werden.

    Richtig ist:
    Objekte, die mit new erzeugt werden, müssen mit delete gelöscht werden.
    Arrays, die mit new[] erzeugt werden, müssen mit delete[] gelöscht werden.
    Du darfst nicht Objekte, die mit new angelegt wurden, mit delete[] löschen und auch nicht Arrays, die mit new[] erzeugt werden, mit delete löschen.

    Besser: gleich lokale Objekte (ohne Pointer), Objektverwaltungsklassen wie std::vector oder std::list, die du doch am Anfang schon im Code hattest, oder Smartpointer verwenden.



  • öhm...... dann habe ich das falsch umgesetzt. also delete[] für arrays und für new einfache delete?
    dann habe ich mir das falsch gemerkt. Das ist mir gerade sehr sehr peinlich 😃
    Entschuldige bitte @manni66

    okay danke. das hat jetzt funktioniert.

    aber bei der Remove Routine wirft er mir noch einen Fehler. Habt ihr da einen Ansatz, woran es liegen könnte?



  • @wob sagte in Structs und listen:

    Besser: [...] Objektverwaltungsklassen wie std::vector

    Ja, bitte! Die bloße Erwähnung von new[]/delete[] in einem Buch für Anfänger ist schon ein deutliches Zeichen, dass der Autor wohl nur bedingt weiss, was er tut. Nicht nur ist es fehleranfällig, so zu programmieren, die Funktionen sind auch nicht einmal besonders effizient:

    Damit delete[] korrekt arbeiten kann, braucht es nämlich die Größe des Array, da für jedes Element der Destruktor aufgerufen werden muss. Diese Größe muss irgendwo gespeichert werden, da new[] lediglich einen Pointer auf das erste Element zurückgibt. D.h. in vielen Implementationen reserviert new[] einen zusätzlichen size_t vor dem eigentlichen Array und legt dort die Größe ab.

    Das ist insofern ineffizient, da erstens der Programmcode meist ebenfalls wissen muss, wie groß das Array ist und diese Zahl wahrscheinlich auch schon irgendwo speichert. Zweitens ist Speicher, der freigegeben soll, nicht selten bereits kalt, d.h. dessen Inhalt befindet sich nicht mehr im Cache. Dennoch muss delete[] die Größe aus eben diesem Speicherbereich auslesen und erzeugt damit einen Cache Miss, den es wahrscheinlich nicht gäbe, wenn die Größe direkt neben dem Pointer liegt (z.B. auf dem Stack), wie es bei std::vector der Fall ist.

    Nicht einmal die Standardbibliothek verwendet unter der Haube new[]/delete[] und ich habe Zweifel, ob die meisten Implementationen selbst das reguläre new verwenden oder sogar überhaupt delete in irgendeiner Form.

    Meiner Meinung nach können new und delete gerne komplett aus der Sprache verschwinden (und aus Lehrbüchern sowieso). Einzige Ausnahme ist das placement new, das aber bestenfalls in Büchern für Fortgeschrittene und angehende Bibliotheksentwicker Erwähnung finden sollte.

    TL;DR: @Avartos Am besten du vergisst new und delete komplett. Dann musst du dir auch nicht die Unterschiede zwischen den Varianten merken. So ziemlich alle Probleme lassen sich ohne diese garantiert besser lösen.



  • Ich zeige diese Aussage mal meinem Prof und frage mal was er dazu sagt^^
    Wir bekommen das im Studium so beigebracht 😃

    Ich finde new bisher ganz praktisch. ^^
    was gibt es dann für eine effizientere Methode für Structs? @Finnegan



  • @Avartos sagte in Structs und listen:

    was gibt es dann für eine effizientere Methode für Structs? @Finnegan

    Wie hier schon mehrfach erwähnt wurde: Nimm std::vector. Diese Datenstruktur sollte immer die erste Wahl sein, wenn man mehrere Objekte des selben Typs speichern will.

    Einfach und simpel:

    #include <string>
    #include <vector>
    #include <iostream>
    
    struct SCity
    {
        std::string name;
        std::string state;
        int population = 0;
    };
    
    auto main() -> int
    {
        std::vector<SCity> cities;
        
        cities.push_back({ "Erfurt", "Thueringen", 214000 });
        cities.push_back({ "Hannover", "Niedersachsen", 538000 });
        cities.push_back({ "Muenchen", "Bayern", 1450000 });
        
        for (const auto& city : cities)
        {
            std::cout 
                << city.name << ", "
                << city.state << ", "
                << city.population << "\n";
        }
    }
    

    Hartcodierte Einträge direkt im Code lassen sich übrigens auch noch etwas kompakter schreiben:

    std::vector<SCity> cities
    {
        { "Erfurt", "Thueringen", 214000 },
        { "Hannover", "Niedersachsen", 538000 },
        { "Muenchen", "Bayern", 1450000 }
    };
    

Anmelden zum Antworten