Problem mit std::list und auto_ptr



  • warum ? was wäre die alternative?

    wenn ich einen normalen zeiger verwende wird glaub ich der dynamische Speicher nicht freigegeben wenn ein zeiger aus dem kontainer gelöscht wird. Oder täusche ich mich da?



  • Zur Frage warum, habe ich dir schon einen hinweis gegeben.
    Beispiel:

    struct A
    {
       int a;
       A() : a(10) {}
    };
    
    void foo(std::auto_ptr<A> a)
    {
    }
    
    int main()
    {
       std::auto_ptr<A> var(new A);
       std::cout << var->a << std::endl;
       foo(var);
       std::cout << var->a << std::endl; /// hier 
       // und jedes mal, wenn du auf das Objekt zugreifst bekommst du ein Problem
       return 0;
    }
    

    Passenderes gibt es dafür in der Standard-lib von c++ nicht.
    Was du suchst sind smart pointer oder aber kannst du eine Funktion schreiben, die den Speicher selbst freigibt.

    Außerdem vorher hast du std::list verwendet. warum bist du jetzt auf std::set umgestiegen?



  • hmm ok dann wäre z.B. boost::scoped_ptr<konto> besser nehme ich an.

    std::set verwende ich nur zur Übung weil ich damit noch nie etwas gemacht habe.


  • Mod

    walljumper schrieb:

    warum ?

    Weil auto_ptr nicht den Anforderungen, den Kontainer an ihre Elemente stellen, genügt. Für auto_ptr ist u.a.

    auto_ptr<foo> t(new foo);
    const auto_ptr<foo> u(new foo);
    auto_ptr<foo> T(t); // ok, aber T und t nicht äquivalent
    auto_ptr<foo> U(u); // error, konstanter auto_ptr nicht kopierbar
    

    walljumper schrieb:

    wenn ich einen normalen zeiger verwende wird glaub ich der dynamische Speicher nicht freigegeben wenn ein zeiger aus dem kontainer gelöscht wird. Oder täusche ich mich da?

    Ein nackter Zeiger verhält sich in einem Kontainer nicht anders als sonst auch.

    walljumper schrieb:

    was wäre die alternative?

    Reihenfolge ohne Belang:
    1. Benutz einen Kontainer, der explizit für Polymorphe Objekte gedacht ist [boost.ptr_container]
    2. Benutz einen Smartpointer, der shared ownership betreibt, z.B. boost::shared_ptr
    3. Benutz einen Smartpointer, der depp copy betreibt
    Für 1. und 3. muss deine Klasse clonebar sein.



  • walljumper schrieb:

    hmm ok dann wäre z.B. boost::scoped_ptr<konto> besser nehme ich an.

    ich kenne mich mit boost nicht aus, aber dem namen nach macht es dasselbe wie auto_ptr

    ich persönlich verwende Loki http://loki-lib.sourceforge.net/
    Dort heißt das Ding was du suchst. SmartPtr



  • cppuser schrieb:

    walljumper schrieb:

    hmm ok dann wäre z.B. boost::scoped_ptr<konto> besser nehme ich an.

    ich kenne mich mit boost nicht aus, aber dem namen nach macht es dasselbe wie auto_ptr

    ich persönlich verwende Loki http://loki-lib.sourceforge.net/
    Dort heißt das Ding was du suchst. SmartPtr

    der Loki::SmartPtr ist nicht so einfach zu benutzen, wie die Smartpointer von boost. In diesem Fall ist der boost::shared_ptr<> die erste Wahl. Denn dort heißt es

    Every shared_ptr meets the CopyConstructible and Assignable requirements of the C++ Standard Library, and so can be used in standard library containers.

    Gruß
    Werner



  • hmm das verwirrt mich jetzt etwas in der dokumentation von boost wird boost::scoped_ptr als smartpointer bezeichnet. naja

    2. Benutz einen Smartpointer, der shared ownership betreibt, z.B. boost::shared_ptr

    scheint das richtige zu sein.



  • kann es sein, dass du nicht verstanden hast warum auto_ptr bzw. scoped_ptr nicht geeignet sind?

    wie gesagt scoped_ptr kenn ich nicht. ICh bin heute mal nett und erkläre auto_ptr

    Im Groben und Ganzen funktioniert auto_ptr folgendermaßen:
    Diese Klasse sorgt dafür, dass der Zeiger, den sie kapselt, dann zerstört wird, wenn der Desturktor von auto_ptr aufgerufen wird.
    Der Desktuktor wird dann aufgerufen, wenn der Gültigkeitsbereich des auto_ptr-Objekts verlassen wird. Diese Technik wird RAII (Resource Acquisition Is Initialization).
    Wenn du beispielweise nun diese Funktion aufrufst:

    void foo(std::auto_ptr<int> a)
    {
    // viel kode
    // ..
    
    // Dann ist hier der Gültigkeitsbereich von a zu 
    // ende. a gibt selbst dann den Speicher den du vorher 
    // angefordert hast frei. (Siehe unten)
    }
    
    int main()
    {
       std::auto_ptr<int> abc(new int);
       *(abc.get()) = 10;
    
       foo(zeiger); // Die Speicherverwaltung wird von dem Parameter übernommen
       // Nach dem Aufruf, ist der Speicher freigegeben. abc zeigt nicht mehr 
       // auf einen gültigen Bereich.
    
       // Warum das so ist
       std::auto_ptr<int> bcd(new int);
       *(bcd.get()) = 10;
       std::auto_ptr<int> cde(bcd); /// Hier passiert nun folgendes:
       /*
          der Zeiger wird an cde übergeben.
          bcd verweist auf null.
       */
    

    Eine vereinfachte implementierung von dem auto_ptr würde ungefähr so aussehen:

    struct MyPtr
    {
       explicit MyPtr(int* p)
          : zeiger_(p) { }
    
       MyPtr(const MyPtr z)
       {
          zeiger_ = z.zeiger_;
          z.zeiger_ = NULL;
       }
    
       int* get()
       { return zeiger_; } 
    private:
       int* zeiger_; 
    };
    

    Hoffentlich war es verständlich.



  • Verdammt, habe bei MyPtr den Destruktor vergessen:

    ~MyPtr()
    {
       delete zeiger_;  // Wenn der Zeiger NULL ist, wird nichts freigegeben.
    }
    

    PS: Und nochwas, denke nicht daran auto_ptr (oder MyPtr) im Zusammenhang mit Arrays zu verwenden. Arrays werden mit delete[] freigegen!



  • Ja hab ich schon verstanden bin nur etwas durcheinander gekommen, weil du gemeint hast ich brauche einen smartpointer.
    In der Dokumentation von boost wird boost::scoped_ptr als smartpointer bezeichnet. Die anderen hier haben aber aber gesagt das auto_ptr nicht geht wegen Problemen beim kopieren diese hat der boost::scoped_ptr aber auch.

    Jetzt frag ich mich nur was gilt den jetzt als smartpointer 😕





  • Eine ausführliche Erläuterung findet man bei Herb Sutter (nach "Container" suchen).

    Herb Sutter nennt auto_ptr<> in Containern in einem anderen Artikel auch "nackt über das Minenfeld laufen" - d.h. es kann gut gehen 🕶

    Gruß
    Werner



  • vielen dank für eure ausführliche hilfe 🙂



  • scoped_ptr kannst du im Übrigen gar nicht in einen Container packen, weil dafür müsste er eine Kopiersemantik besitzen, was ein scoped_ptr nicht hat.

    Wenn du eh boost verwendest nimm die pointer container von boost.


Anmelden zum Antworten