Frage zu SMARTPTR / Smart pointer



  • Ich arbeite gerade an einem c++ Projekt, in dem Smart Pointers verwendet werden.

    Mir fehlt aber viel wissen über sie und ich habe bis jetzt zu wenig info gefunden, die mir das ganze verständlich erklärt, wie ich die verwenden könnte. Ich fühle mich auch etwas zu blöd, um auch eine richtige suchanfrage zu formulieren.

    Daher versuche ich mein Glück hier und stelle euch ein paar fragen. Seid mir bitte nicht sehr böse 🙂

    Frage nr. 1
    Wie kann man die smartpointer analog zu normalen Zeiger verstehen?
    Ist folgendes grob gesehen mehr oder weniger richtig?

    SMARTPTR(classA) objA <--> classA *objA (bzw. classA *objA = NULL)
    

    oder ist das falsch. Kann man das überhaupt vergleichen?

    Frage nr. 2
    Wenn der Gedanke aus der 1.Frage richtig ist, wie mache ich so was mit SmartPointers?

    classA objA1();
    classA *objA2 = &objA1();
    

    bzw.

    classA *objA1 = new classA();
    classA *objA2 = objA1;
    

    Oder die Frage umformuliert: wie komme ich auf Speicheradresse von einem Smartpointer?

    Frage nr. 3
    Und ich vermute mal, wenn ich die Antwort auf die zweite Frage hab, hab ich auch eine Antwort auf die dritte.
    Es gibt im Projekt eine Typdefinition:

    typedef list<SMARTPTR(Ding), GCALLOC(SMARTPTR(Ding)) > DingList;
    

    Nun gibt es eine Listen von dem obengenannten DingList, bestehend aus SMARTPTR(Ding)
    Ich muss eine zweite Liste erzeugen, die Teil von Dings aus der ersten Liste enthält, aber so, dass die Dings in beiden Listen dieselbe Speicheradresse haben.

    Ich hoffe, ich habe meine Fragen mehr oder weniger gut formuliert und hoffe sehr, eine(r) von euch kann mir helfen.

    Schöne Grüße



  • > Wie kann man die smartpointer analog zu normalen Zeiger verstehen?

    Ein Smartpointer ist ein Wrapper um einen rohen Zeiger. Sie sind in Sachen Ausnahmesicherheit und Speicherverwaltung sehr wichtig, da die Ressourcen, die in ihnen gespeichert werden, meist Zeiger auf dynamisch generierte Objekte sind, die man manuell zu irgendeinem Zeitpunkt freigeben muss.
    Da man das schnell vergessen oder aber eine Ausnahme geworfen werden könnte, bevor man den Speicher freigibt, nutzt man die Tatsache aus, dass Objekte, die auf dem Stack angelegt werden, wie etwa ein Smartpointer, automatisch am Ende des Gültigkeitsbreieches freigegeben werden.
    Dank Elementfunktions-Templates und nicht expliziten generalisierten (Kopier-)Konstruktoren legen sie ein intuitives Zeiger-Verhalten zu Tage, implizite Konvertierungen einer Klassenhierachie durchführen zu können:

    class base { };
    class derived { };
    
    smart_ptr<base> ptr1(new base);
    smart_ptr<base> ptr2(new derived); // base* -> derived*
    

    Um das intuitive Verhalten noch zu verbessern, wurden u.a. Operatoren wie operator ->() überladen, damit hat man direkten Zeiger-Zugriff.

    > Frage nr. 2

    Einen Smartpointer legst du im allgemeinen so an:

    smart_ptr<type> ptr(new type());
    smart_ptr<type> ptr2(ptr); // Kopiere Pointer (Achtung! Unterschiedliches Verhalten!)
    

    An die Adresse des Pointers kommst du so: 😛

    smart_ptr<type> *ptr_of_the_ptr = &ptr;
    

    Das ist aber bestimmt nicht das, was du willst. An den Zeiger, der im Pointer gespeichert wird, kommst du eben z.B. mit operator ->() oder get()

    type *raw_ptr = ptr.get();
    raw_ptr->some_memfun();
    ptr->some_memfun(); // Überladener -> Operator bringt auch Zeigerzugriff
    

    Zu 3.

    Es gibt verschiedene Zeigerarten. Der für deinen Zweck sinnvollste ist boost::shared_ptr oder tr1::shared_ptr . Je nach dem, wie viele Smartpointer den rohen Zeiger beinhaltet, wird ein Referenzzähler hoch bzw. runtergezählt. Wenn kein shared_ptr mehr drauf zeigt, wird das Objekt gelöscht. (Destruktoraufruf + Speicherfreigabe).



  • Vielleicht hilft dir auch der Artikel des C++-Magazins über Smart-Pointer.



  • Es gibt verschiedene Zeigerarten. Der für deinen Zweck sinnvollste ist boost::shared_ptr oder tr1::shared_ptr .

    Ich habe mir noch die Header-Dateien, in denen Beschreibung für Smart-Pointers stehen und die in das Projekt eingebunden sind, angeschaut. Ich vermute mal, es war eine frühere Version von den Smartpointers. Es gibt Ptr und InactivePtr. Andere Arten sehe ich nicht. Statt get gibt es GetRawPtr(). Wahrscheinlich waren die Ptr die Vorfahren von shared_ptr

    > Frage nr. 2

    Einen Smartpointer legst du im allgemeinen so an:

    smart_ptr<type> ptr(new type());
    smart_ptr<type> ptr2(ptr); // Kopiere Pointer (Achtung! Unterschiedliches Verhalten!)
    

    Entschuldigung, was heißt "Kopiere Pointer"? Dass die Adresse kopiert wird?

    Das ist aber bestimmt nicht das, was du willst. An den Zeiger, der im Pointer gespeichert wird, kommst du eben z.B. mit operator ->() oder get()

    Sorry, ich bin jetzt gerade völlig durcheinander. Daher noch mal alle Fragen zusammengefasst. Ich sehe schon Steine in mich fliegen, aber vielleicht werdet ihr wieder so nett und schreibt, was falsch ist, wie es richtig sein sollte.

    #define SMARTPTR(type) Ptr<type>
    typedef list<SMARTPTR(Ding), GCALLOC(SMARTPTR(Ding)) > DingList;	
    DingList ding_list = getDingList();
    

    Angenommen, ich habe bereits eine Liste ding_list. Diese kann beliebig geändert werden, aber zu irgendeinem Zeitpunkt brauche ich eine Kopie davon, an der nichts gemacht werden dürfte. Die erste Liste und deren Inhalt darf weiter geändert werden.

    DingList kopie_ding_list;
    DingList::iterator dl_it;
    
    for(dl_it = ding_list.begin(); dl_it = ding_list.end(); dl_it++)
    {
        SMARTPTR(Ding) tmp_ding = *dl_it;
        kopie_ding_list.push_back(tmp_ding);
    }
    

    Zu einem späteren Zeitpunkt wird es entschieden, dass die erste Liste jetzt aus ihrer Kopie wiederherstellt werden sollte

    ding_list.clear();
    DingList::iterator dl_it;
    
    for(dl_it = kopie_ding_list.begin(); dl_it = kopie_ding_list.end(); dl_it++)
    {
        SMARTPTR(Ding) tmp_ding = *dl_it;
        ding_list.push_back(tmp_ding);
    }
    

    Mittlerweile bezweifle ich stark, dass ich das ganze richtig implementiert hatte. Aber nun kommt der nächste Punkt. Nachdem ich die erste Liste wiederherstellt hatte, muss ich noch eine erzeugen, die nur aus einem Teil der ersten besteht (zb.jedes zweites Element), aber so dass ihre Elemente auf dieselben Objekte zeigen, wie in der ersten. Dazu folgender code

    DingList teil_ding_list;
    DingList::iterator dl_it;
    
    for(dl_it = ding_list.begin(); dl_it != ding_list.end(); dl_it++)
    {
        if (!ding_list.end()) dl_it++;
        SMARTPTR(Ding) tmp_ding = dl_it.get();
        teil_ding_list.push_back(tmp_ding);
    }
    

    Ich danke euch schon im Voraus.



  • ametim schrieb:

    Es gibt verschiedene Zeigerarten. Der für deinen Zweck sinnvollste ist boost::shared_ptr oder tr1::shared_ptr .

    Ich habe mir noch die Header-Dateien, in denen Beschreibung für Smart-Pointers stehen und die in das Projekt eingebunden sind, angeschaut. Ich vermute mal, es war eine frühere Version von den Smartpointers. Es gibt Ptr und InactivePtr. Andere Arten sehe ich nicht. Statt get gibt es GetRawPtr(). Wahrscheinlich waren die Ptr die Vorfahren von shared_ptr

    Nein. Klingt eher so als waeren deine Smartpointer-Klassen auf dem eigenen Mist der Entwickler deines Projekts gewachsen. Die meisten der Ratschlaege in diesem Thread beziehen sich auf std::smart_ptr (die Smartpointer-Klasse die Teil des C++ standards ist) bzw. auf die Smartpointer-Klassen aus der boost-Bibliothek (die Teil es C++ TR1 sind und somit auch Teil des neuen C++ Standards werden). Wie die Smartpointer-Klasse, die du verwendest, im Detail aussieht/funktioniert, koennen wir nur raten!

    > Frage nr. 2

    Einen Smartpointer legst du im allgemeinen so an:

    smart_ptr<type> ptr(new type());
    smart_ptr<type> ptr2(ptr); // Kopiere Pointer (Achtung! Unterschiedliches Verhalten!)
    

    Entschuldigung, was heißt "Kopiere Pointer"? Dass die Adresse kopiert wird?

    Genau

    Das ist aber bestimmt nicht das, was du willst. An den Zeiger, der im Pointer gespeichert wird, kommst du eben z.B. mit operator ->() oder get()

    Sorry, ich bin jetzt gerade völlig durcheinander. Daher noch mal alle Fragen zusammengefasst. Ich sehe schon Steine in mich fliegen, aber vielleicht werdet ihr wieder so nett und schreibt, was falsch ist, wie es richtig sein sollte.
    [....]

    Wir koennen dir nicht genau sagen wie das geht, kommt drauf an wie deine Smartpointer-Klasse genau aussieht, besonders das Copy-Ctor-Verhalten. In der Regel ists heikel, zwei Smartpointer zu haben, die auf den gleichen Pointer aufpassen!



  • Es war gestern schon zu spät um noch etwas zu schreiben. Ich glaube, ich habe alle meine Fehler verstanden, was mir leider nicht weiter hilft.

    Sorry, ich bin jetzt gerade völlig durcheinander. Daher noch mal alle Fragen zusammengefasst. Ich sehe schon Steine in mich fliegen, aber vielleicht werdet ihr wieder so nett und schreibt, was falsch ist, wie es richtig sein sollte.

    #define SMARTPTR(type) Ptr<type>
    typedef list<SMARTPTR(Ding), GCALLOC(SMARTPTR(Ding)) > DingList;	
    DingList ding_list = getDingList();
    

    Angenommen, ich habe bereits eine Liste ding_list. Diese kann beliebig geändert werden, aber zu irgendeinem Zeitpunkt brauche ich eine Kopie davon, an der nichts gemacht werden dürfte. Die erste Liste und deren Inhalt darf weiter geändert werden.

    DingList kopie_ding_list;
    DingList::iterator dl_it;
    
    for(dl_it = ding_list.begin(); dl_it = ding_list.end(); dl_it++)
    {
        SMARTPTR(Ding) tmp_ding = *dl_it;
        kopie_ding_list.push_back(tmp_ding);
    }
    

    Wahrscheinlich sehr falsch. Denn ich kopiere nur den Pointer, muss aber erst einen Objekt als kopie von dem, auf das Pointer zeigt, erstellen und einen Pointer auf dieses dann in der Kopie-Liste speichern.

    Zu einem späteren Zeitpunkt wird es entschieden, dass die erste Liste jetzt aus ihrer Kopie wiederherstellt werden sollte

    ding_list.clear();
    DingList::iterator dl_it;
    
    for(dl_it = kopie_ding_list.begin(); dl_it = kopie_ding_list.end(); dl_it++)
    {
        SMARTPTR(Ding) tmp_ding = *dl_it;
        ding_list.push_back(tmp_ding);
    }
    

    Muss fast genau so gemacht werden, schätze ich mal.

    Nachdem ich die erste Liste wiederherstellt hatte, muss ich noch eine erzeugen, die nur aus einem Teil der ersten besteht (zb.jedes zweites Element), aber so dass ihre Elemente auf dieselben Objekte zeigen, wie in der ersten. Dazu folgender code

    DingList teil_ding_list;
    DingList::iterator dl_it;
    
    for(dl_it = ding_list.begin(); dl_it != ding_list.end(); dl_it++)
    {
        if (!ding_list.end()) dl_it++;
        SMARTPTR(Ding) tmp_ding = dl_it.get(); // .get() muss weg
        teil_ding_list.push_back(tmp_ding);
    }
    

    Und das ist wahrscheinlich der mehr oder weniger richtige Abschnitt.



  • ametim schrieb:

    Ich glaube, ich habe alle meine Fehler verstanden, was mir leider nicht weiter hilft.

    Ich glaube auch das wir dir nicht helfen können wenn es um eigene Smartpointerklassen geht, die wir auch nicht kennen. Ebenso wie GCALLOC auch nicht zum C++ Standard gehört. Da musst du dich wohl im Projekt rumfragen, oder die Sourcen studieren.

    Wenn ich richtig liege könnte dir aber vielleicht diese Referenz weiterhelfen (Letzte Änderung scheint von 2001 zu sein). Grundsätzlich würde ich aber eher zu den Implementierungen von boost & tr1 (sofern verfügbar) greifen.



  • asc schrieb:

    Ich glaube auch das wir dir nicht helfen können wenn es um eigene Smartpointerklassen geht, die wir auch nicht kennen. Ebenso wie GCALLOC auch nicht zum C++ Standard gehört. Da musst du dich wohl im Projekt rumfragen, oder die Sourcen studieren.

    Wenn ich richtig liege könnte dir aber vielleicht diese Referenz weiterhelfen (Letzte Änderung scheint von 2001 zu sein). Grundsätzlich würde ich aber eher zu den Implementierungen von boost & tr1 (sofern verfügbar) greifen.

    Auf jeden Fall Danke an Euch alle. Es hilft bereits einem, wenn er das Problem in einem Forum postet. Man bekommt irgendwie neue Impulse.

    @Asc danke für den Link. Leider darf ich nicht viel an dem Projekt ändern, deswegen bleibt erstmal bei der alten Biblithek.


Log in to reply