Einbinden von dynamischen Objekten in Containern



  • Hallo,
    ich habe ein kleines Problem bei dem ich nicht weiterkomme. Und zwar möchte ich dynamisch erzeugte Objekte bzw. Zeiger auf diese in einem Container (deque) ablegen. Nur leider funktioniert das überhaupt nicht. In den Containern werden doch nur Kopien von den erzeugten Objekten abgelegt. Deswegen müsste es doch auch ausreichen wenn ich den Zeiger der auf dieses Objekt gerichtet ist dort ablege. Wie kann ich das umsetzen?
    Hier mein kläglicher Versuch:

    #include <deque>
    using namespace std;
    
    class X
    { private: char a[30];
               double b;
      public: void inp();
              void outp();
              zug();
              zug(const zug& inp);
              ~zug(){};
    };
    
    X :: X(void)
    { b = 0.0; }
    
    void X :: inp()
    { cout << "Eingabe: Bez." << flush;
      cin >> a;
      cout << "Eingabe: Wert" << flush;
      cin >> b;
    }
    
    void X :: outp()
    { cout << "Bez. " << a << "Wert " << b << flush; }
    
    int main()
    { car ausw = 0'0;
      deque <X> d;
      X Xobj* = new X;
      X inp = inp;
      cout << "Auswahl" << endl;
      cin >> ausw;
      switch(ausw)
      {  case 1: Xobj -> inp(); d.push_front(Xobj& inp); break;
         case 2: Xobj -> inp(); d.push_back(Xobj& inp); break;
         case 3: Xobj -> outp(); d.pop_front(); break;
         case 4: Xobj -> outp(); d.pop_back(); break;
         default: cout << "Error" << flush; break;
      }
      delete X;
    }
    


  • Ich hab die weiteren Header die ich eingebunden hab vergessen:

    #include <stdio.h>
    #include <tchar.h>
    #include <conio.h>
    #include <iostream>
    #include <iomanip>
    #include <deque>
    using namespace std;
    

    Die machen zwar teilweise noch keinen SInn, aber das Programm soll noch wachsen 🙂
    Danke für Eure Bemühungen.



  • deque <X*> d;
    X* px = new X;
    d.push_back(px);
    
    ...
    
    d.clear();
    delete px;
    

    So!

    X Xobj* = new X;
    ...
    d.push_front(Xobj& inp);
    

    Das sieht sehr komisch aus.



  • Vagabund schrieb:

    In den Containern werden doch nur Kopien von den erzeugten Objekten abgelegt.

    Richtig (lassen wir jetzt Move-Semantik und Optimierungen aussen vor).

    Vagabund schrieb:

    Deswegen müsste es doch auch ausreichen wenn ich den Zeiger der auf dieses Objekt gerichtet ist dort ablege.

    Nein, die Schlussfolgerung ist falsch. Wenn du Zeiger speicherst, werden nur die Zeiger kopiert, und nicht der referenzierte Speicherbereich. Vermeide besitzende Zeiger in Containern, wo es nur geht, denn sie bringen nicht wenige Probleme mit sich.

    d.push_front(Xobj& inp)
    

    Das ist keine gültige C++-Syntax. Wahrscheinlich willst du sowas erreichen:

    X Xobj;
    std::deque<X> d;
    
    d.push_front(Xobj);
    


  • Danke schonmal

    Richtig war es auch so hatte mich vertippt:

    int main()
    {
    ...
    X *Xobj = new X;
    ...
    }
    

    Leider klappt es mit

    deque <X*> d;
    

    immernoch nicht. Der Error für

    d.push_front(X& eingabe);
    

    lautet: 'Kein "&" - Operator stimmt mit diesen Operanden überein.'



  • Danke Nexus, aber die folgendes

    X Xobj;
    std::deque<X> d;
    
    d.push_front(Xobj);
    

    würde das Objekt nur statisch erzeugen bzw. einbinden. Ich würde das gern mit dynamischen erzeugten Objekten machen.



  • Danke knivil es funktioniert.



  • Nexus schrieb:

    Vermeide besitzende Zeiger in Containern, wo es nur geht, denn sie bringen nicht wenige Probleme mit sich.

    Um das nochmal zu unterstreichen.



  • Vagabund schrieb:

    Ich würde das gern mit dynamischen erzeugten Objekten machen.

    Gibt es einen Grund, wieso automatisch verwaltete Objekte nicht ausreichen? Du machst dir das Leben echt unnötig schwer, zumindest sobald du etwas Komplexeres mit deinem Container tust oder z.B. Exceptions verwendest.

    Ansonsten siehe Wichtig. 😉



  • Wichtig. schrieb:

    Nexus schrieb:

    Vermeide besitzende Zeiger in Containern, wo es nur geht, denn sie bringen nicht wenige Probleme mit sich.

    Um das nochmal zu unterstreichen.

    Dann will ich es auch verstehen...
    Was versteht ihr unter besitzende Zeiger?
    Wenn ich einen std::vector mit Zeigern habe und alle Objekte darin
    per Definition dem Objekt gehören, in dem es sich befindet,
    was ist daran schlimm?
    Das Objekt hat dann die Verantwortung für das Löschen aller Elemente
    in diesem Vektor.
    Natürlich muss man bei multi-threaded Applikationen aufpassen, dass
    die Lebensdauer "ausreichend" ist für andere Threads.



  • Wichtig??? schrieb:

    Dann will ich es auch verstehen...
    Was versteht ihr unter besitzende Zeiger?

    Zeiger, über die die Lebensdauer des referenzierten Objekts kontrolliert wird. Der Gegensatz dazu wären Zeiger, die lediglich als Verweise dienen und keine Speicherverwaltungsaufgabe übernehmen.

    int* p = new int;
    // p besitzend; man muss p wieder freigeben
    delete p;
    
    int x;
    int* q = &x;
    // q nicht besitzend; nur passiver Verweis
    

    Wichtig??? schrieb:

    Wenn ich einen std::vector mit Zeigern habe und alle Objekte darin
    per Definition dem Objekt gehören, in dem es sich befindet,
    was ist daran schlimm?
    Das Objekt hat dann die Verantwortung für das Löschen aller Elemente
    in diesem Vektor.

    Es ist nicht per se schlimm. Aber es birgt einige Gefahren, die gerade von Anfängern stark unterschätzt werden. Darunter fallen vor allem folgende Punkte:

    • Memory Leaks, wenn man den Speicher nicht deallokiert. Das Problem sind neben dem vergessenen delete vor erase() hauptsächlich Funktionen mit mehreren return -Statements und/oder Exceptions, welche das Container-Objekt zerstören können, ohne den Speicher freizugeben.
    • Undefiniertes Verhalten, die durch Besitz-Unklarheiten bei der Modifikation der Sequenz entstehen. Beispiel dafür ist der STL-Algorithmus std::remove() .
    • Das Kopieren von Containern oder Teilen davon führt zu komplexen Abhängigkeiten, die eine korrekte Freigabe stark erschweren. Ähnlich wie der obere Punkt.

    Andere Nachteile sind:

    • Vorteil der Container, die einem Speicherverwaltung abnehmen, geht verloren
    • Zusätzliche Dereferenzierung beim Zugriff auf Objekte
    • Geschwindigkeits- und Speicheroverhead, da Allokation für jedes einzelne Objekt

    Es gibt natürlich Anwendungsfälle, in denen man Zeiger wirklich braucht (Polymorphie, Nicht-Kopierbarkeit, grosse und möglicherweise fehlschlagende Objekt-Kopien, ...). Wenn der Code überblickbar ist, können besitzende Zeiger in STL-Containern gerade noch angebracht sein. Ansonsten kann man auch einen Blick auf die Bibliothek Boost.PointerContainers werfen.


Log in to reply