Dies ist eine alte, beantwortete Frage, aber @Alexandre fragte: "Warum sollte jemand dies tun wollen?", Und ich dachte, ich könnte eine Beispielverwendung bereitstellen, die ich heute Nachmittag in Betracht ziehe.
Legacy-Code. Verwendet nackte Zeiger Obj * obj mit einem Löschobjekt am Ende.
Leider muss ich manchmal, nicht oft, das Objekt länger am Leben halten.
Ich denke darüber nach, es zu einem intelligenten Zeiger mit Referenzzählung zu machen. Aber es gäbe viel Code zu ändern, wenn ich ihn ref_cnt_ptr<Obj>
überall verwenden würde. Und wenn Sie nacktes Obj * und ref_cnt_ptr mischen, können Sie das Objekt implizit löschen lassen, wenn das letzte ref_cnt_ptr verschwindet, obwohl Obj * noch am Leben ist.
Ich denke also darüber nach, ein explizites_delete_ref_cnt_ptr zu erstellen. Dh ein Referenzzählzeiger, bei dem das Löschen nur in einer expliziten Löschroutine erfolgt. Verwenden Sie es an einer Stelle, an der der vorhandene Code die Lebensdauer des Objekts kennt, sowie in meinem neuen Code, der das Objekt länger am Leben hält.
Das Inkrementieren und Dekrementieren des Referenzzählers als explizit_delete_ref_cnt_ptr wird manipuliert.
Aber NICHT freigeben, wenn der Referenzzähler im Destruktor explic_delete_ref_cnt_ptr Null ist.
Nur freigeben, wenn der Referenzzähler in einer expliziten löschähnlichen Operation als Null angezeigt wird. ZB in so etwas wie:
template<typename T> class explicit_delete_ref_cnt_ptr {
private:
T* ptr;
int rc;
...
public:
void delete_if_rc0() {
if( this->ptr ) {
this->rc--;
if( this->rc == 0 ) {
delete this->ptr;
}
this->ptr = 0;
}
}
};
OK, so etwas. Es ist etwas ungewöhnlich, dass ein Zeigertyp mit Referenzzählung das Objekt, auf das im rc'ed ptr-Destruktor verwiesen wird, nicht automatisch löscht. Aber es scheint, als würde dies das Mischen von nackten Zeigern und rc'ed-Zeigern etwas sicherer machen.
Bisher ist dies jedoch nicht erforderlich.
Aber dann kam mir der Gedanke: Wenn das Objekt, auf das der Pointee zeigt, weiß, dass es als Referenz gezählt wird, z. B. wenn sich die Zählung innerhalb des Objekts (oder in einer anderen Tabelle) befindet, könnte die Routine delete_if_rc0 eine Methode der sein Pointee-Objekt, nicht der (intelligente) Zeiger.
class Pointee {
private:
int rc;
...
public:
void delete_if_rc0() {
this->rc--;
if( this->rc == 0 ) {
delete this;
}
}
}
};
Eigentlich muss es überhaupt keine Mitgliedsmethode sein, könnte aber eine freie Funktion sein:
map<void*,int> keepalive_map;
template<typename T>
void delete_if_rc0(T*ptr) {
void* tptr = (void*)ptr;
if( keepalive_map[tptr] == 1 ) {
delete ptr;
}
};
(Übrigens, ich weiß, dass der Code nicht ganz richtig ist - er wird weniger lesbar, wenn ich alle Details hinzufüge, also lasse ich ihn so.)
delete this
eine enge Kopplung zwischen der Klasse und der Zuordnungsmethode erstellt haben, die zum Erstellen von Objekten dieser Klasse verwendet wird. Das ist ein sehr schlechtes OO-Design, da das Grundlegendste in OOP darin besteht, autonome Klassen zu erstellen, die nicht wissen oder sich nicht darum kümmern, was ihr Anrufer tut. Daher sollte eine richtig gestaltete Klasse nicht wissen oder sich darum kümmern, wie sie zugewiesen wurde. Wenn Sie aus irgendeinem Grund einen so besonderen Mechanismus benötigen, wäre es meines Erachtens besser, eine Wrapper-Klasse um die eigentliche Klasse herum zu verwenden und den Wrapper mit der Zuordnung befassen zu lassen.