const_cast hier sicher?
-
hi!
ich brauche eine STL list aus smart pointern (exception safety...). leider kann ich nur die standard bibliothek verwenden (kein tr1 oder boost) und muss mir deshalb selber einen bauen (sonst tr1::shared_ptr und ich wär glücklich).
gut, nun stoße ich auf folgendes problem:
die pointer dürfen selber keine exceptions werfen (daher reference linking. intrusives reference counting käme auch in frage, aber das könnte ich hier nur umständlich/schwer umsetzen).
gut, nun brauch ich natürlich einen copyctor. der müsste logischerweise folgende signatur haben:
SmartPtr(SmartPtr&);da ich ja den zu kopierenden pointer verändern muss.
damit ich eine std::list<SmartPtr> machen kann bräuchte der aber den "normalen" copyctor:SmartPtr(const SmartPtr&);deswegen folgender workaround (man beachte den copyctor und den const_cast darin)
template<class T> class SmartPointer { public: SmartPointer(T *ptr) : ptr_(ptr), prev_(0), next_(0) {}; SmartPointer(SmartPointer const &right) : ptr_(right.ptr_), prev_(const_cast<SmartPointer*>(&right)), next_(0) { prev_->next_ = this; }; ~SmartPointer() { if(prev_ == 0 && next_ == 0) delete ptr_; else { if(next_) next_->prev_ = prev_; if(prev_) prev_->next_ = next_; } }; T &operator *() const { return *ptr_; }; T *operator ->() const { return ptr_; }; T *get() const { return ptr_; }; bool operator ==(SmartPointer const &right) const { return right.ptr_ == ptr_; }; private: SmartPointer &operator =(SmartPointer &right); T *ptr_; SmartPointer *prev_; SmartPointer *next_; };da die logische constness gewahrt bleibt (ptr_ selber wird ja nicht verändert), denke ich, dass man das so machen kann.
denkt ihr auch so, oder weis evtl. jemand wie man das besser lösen kann!?danke schonmal

-
Nein, das wäre nicht sicher. Wegen folgendem Fall
SmartPtr const s; // ... SmartPtr foo = s;das wäre afaik "undefined behaviour"
Aber ich verstehe nicht wie du den SmartPtr überhaupt implementierst. Was soll das mit der Liste?
Selbst wenn du tr1 oder boost nicht verwenden darfst (warum auch immer), kannst du ja zumindest den Code von dort kopieren oder dir zumindest einmal anschauen wie dort der SmartPtr implementiert ist (ansonsten gibt es in Modern C++ Design eine Implementierung eines Smart-Pointers).
-
Ich weiss nicht wie performance-kritisch das bei Dir ist; aber man könnte z.B. eine "Deiecksbeziehung" mit der jeweils für sie instanziierten Klasse daraus machen:
template<class T> class SmartPointer { private: static std::map<T*,unsigned> ptr_map_; // zeiger als key, unsigned als refcount //... };Dann lässt man die c/dtoren jeweils den Eintrag für "ihren" Zeiger in der Map verwalten.
Kostet aber und muss synched werden.
Grüsse
*this
-
mutable hilft:
template<class T> class SmartPointer { public: SmartPointer(T *ptr) : ptr_(ptr), prev_(this), next_(this) {} SmartPointer(SmartPointer const &right) : ptr_(right.ptr_), prev_(&right), next_(right.next_) { next_->prev_ = this; prev_->next_ = this; } ~SmartPointer() { if(next_ != this) { next_->prev_ = prev_; prev_->next_ = next_; } else if(ptr_) delete ptr_; } // usw. private: T *ptr_; const SmartPointer* mutable prev_; const SmartPointer* mutable next_; };P.S. Ich nehme an, der private Zuweisungsoperator ist ein Unfall. Auf den darfst du eigentlich nicht verzichten, wenn du Container benutzt.
-
rüdiger schrieb:
Aber ich verstehe nicht wie du den SmartPtr überhaupt implementierst. Was soll das mit der Liste?
Selbst wenn du tr1 oder boost nicht verwenden darfst (warum auch immer), kannst du ja zumindest den Code von dort kopieren oder dir zumindest einmal anschauen wie dort der SmartPtr implementiert ist
das war natürlich das erste was ich gemacht hab. aber die boost::shared_ptr können eine exception werfen, meine dürfen das nicht. deswegen verwende ich das reference linking (das zeug mit der liste oben).
Gast++ schrieb:
Ich weiss nicht wie performance-kritisch das bei Dir ist; aber man könnte z.B. eine "Deiecksbeziehung" mit der jeweils für sie instanziierten Klasse daraus machen:
performance is nicht soo das problem. es sollte eher einfach sein (meine kollegen müssens verstehen und die sind eher anfänger) das problem bei deinem ansatz mit der map ist, dass ja die std::map throwen könnte...
genauso wie dein code oben hat mein erster versuch ausgesehen. leider kompilliert das nicht... (error C2059: syntax error : 'mutable ')
das mit dem zuweisungsoperator ist mir bewusst.jedenfalls schonmal danke für die antworten

-
dot schrieb:
genauso wie dein code oben hat mein erster versuch ausgesehen. leider kompilliert das nicht... (error C2059: syntax error : 'mutable ')
das mit dem zuweisungsoperator ist mir bewusst.Stimmt, mutable ist ja auch kein Deklarator sondern ein "storage-class-specifier" wie extern,auto,register,static; also muss es so aussehen:
mutable const SmartPointer* prev_; mutable const SmartPointer* next_;
-
dot schrieb:
das problem bei deinem ansatz mit der map ist, dass ja die std::map throwen könnte...
Du könntest doch eine static Zugriffsfunktion schaffem und darin fangen. Diese dann in den c/dtoren verwandt und sie laufen sauber durch.
Grüsse
*this
-
camper schrieb:
mutable const SmartPointer* prev_; mutable const SmartPointer* next_;komisch, das hab ich auch schon probiert. ging vorhin nicht. jetzt gehts. danke

-
Gast++ schrieb:
Du könntest doch eine static Zugriffsfunktion schaffem und darin fangen. Diese dann in den c/dtoren verwandt und sie laufen sauber durch.
das versteh ich jetzt nicht so ganz. was mach ich dann wenn ich gefangen hab?
-
dot schrieb:
Gast++ schrieb:
Du könntest doch eine static Zugriffsfunktion schaffem und darin fangen. Diese dann in den c/dtoren verwandt und sie laufen sauber durch.
das versteh ich jetzt nicht so ganz. was mach ich dann wenn ich gefangen hab?
Ich behaupte mal dass wenn std::map - bei defensiver Programierung - wirft die gesamte Anwendung ein erhebliches Problem hat.
Man könnte an der Stelle dann noch Reallokation versuchen oder halt "gracefully exiting".
Du allozierst ja nicht das Objekt sondern nur die ca. 8/12 Byte für den Zeiger und den refcount.
Und wie gesagt, synched werden muss das Ganze natürlich sowieso.EDIT Jezt weiss ich glaube ich was Du meinst; Du darfst natürlich keine Iteratoren vorhalten - die werden natürlich sehr schnell invalide! Aber das hast Du ja wohl auch nicht vor, oder? /EDIT
Grüsse
*this
-
Gast++ schrieb:
Ich behaupte mal dass wenn std::map - bei defensiver Programierung - wirft die gesamte Anwendung ein erhebliches Problem hat.
Man könnte an der Stelle dann noch Reallokation versuchen oder halt "gracefully exiting".
Du allozierst ja nicht das Objekt sondern nur die ca. 8/12 Byte für den Zeiger und den refcount.
Und wie geasgt, synched werden muss das Gnaze natürlich sowieso.jep, das denk ich auch. und wenn das ein persönliches projekt wär, dann hätt ich absolut 0 problem damit. leider isses was für die uni und die haben da haufenweise sinnlose vorgaben (z.b. sind inline funktionen außer bei templates verboten...)
naja, danke jedenfalls. mit campers lösung bin ich schon zufrieden

-
Die Vorgabe "darf beim konstruieren nicht werfen" ist alles andere als Sinnlos.
Egal was wo noch welche Probleme haben wird, wenn ich den SmartPtr nicht mit no-throw anlegen kann, dann kann ich ihn auch nirgends verwenden wo ich eine no-throw Funktion implementieren muss.
Und das kommt in diversen Libraries öfter mal vor, z.B. in cleanup Code.
-
hustbaer schrieb:
Die Vorgabe "darf beim konstruieren nicht werfen" ist alles andere als Sinnlos.
diese vorgabe stammt aus genau diesen gründen (cleanup...) ja auch von mir
