Smartpointer läuft nicht, wie er soll
-
Hey ihr,
Ich habe einen Smartpointer programmiert.
Doch leider funktioniert er irgendwie nicht.
Wenn ich folgenden Quelltext ausführe, müsste eigentlich der =-Operator dafür sorgen, dass bei Zuweisung eines Objektes der Counter des linken Objektes decrementiert, und der Counter des rechten Objektes incrementiert wird.
Doch dummerweise werden irgendwie beide incrementiert
Die Ausgabe lautet nämlich:
Es gibt 2 Objekte.
Es gibt 2 Objekte.
Es gibt 1 Objekte.wo sie eigentlich so sein sollte:
Es gibt 2 Objekte.
Es gibt 0 Objekte.
Es gibt 1 Objekte.Doch irgendwie läuft das nicht :-(^^
Hier ist mein Quelltext:
#include <iostream> #include <string> class Smartpoint; class Counter { private: friend class Smartpoint; int use; int *i_point; ~Counter(){} Counter(int* u) : use(1), i_point(u){} public: int getvar(void) { return use; } }; class Smartpoint { private: int i_var; Counter * c; public: Smartpoint(int var, int *count) : i_var(var), c(new Counter(count)) {} Smartpoint(const Smartpoint& ref) { i_var = ref.i_var; c = ref.c; ++ref.c->i_point; } ~Smartpoint() { if(--c->use == 0) delete c; } Smartpoint& operator=(const Smartpoint& ref) { ++ref.c->use; if(--c->use == 0) delete c; i_var = ref.i_var; c = ref.c; return *this; } void seti_var(int); void setc(int*); int geti_var(void); int* getc(void); Counter* Smartpoint::getcc(void) { return c; } }; void Smartpoint::seti_var(int i) { i_var = i; } void Smartpoint::setc(int *i) { c->i_point = i; } int Smartpoint::geti_var(void) { return i_var; } int* Smartpoint::getc(void) { return c->i_point; } using namespace std; void tellme(Smartpoint, Smartpoint, Smartpoint); int main(void) { cout << "Das folgende Programm soll zeigen, was ein Smartpointer ist, und wie damit umgegangen werden kann!" << endl; int * drei = new int(3); int * vier = new int(4); int * fuenf = new int(5); Smartpoint S(3,drei); //Smartpointobjekt erstellen. Smartpoint Z(4,vier); //Noch ein Smartpointobjekt erstellen Smartpoint U(5,fuenf); //Noch ein Smartpointobjekt erstellen Z = S; tellme(S,Z,U); system("Pause"); } void tellme(Smartpoint S, Smartpoint Z, Smartpoint U) { cout << "Es gibt " << S.getcc()->getvar() << " Objekte." << endl; cout << "Es gibt " << Z.getcc()->getvar() << " Objekte." << endl; cout << "Es gibt " << U.getcc()->getvar() << " Objekte." << endl; }bye
David
-
Bist Du sicher, dass Du im Copy-Ctor von Smartpointer den Zeiger inkrementieren möchtest, und nicht den Zähler?
-
Wiso?
Mein Kopierkonstruktor wird ja garnicht aufgerufen.
Nur der = Operator, welchen ich überladen habe.
Incrementiert oder decrementiert wird ja nur die Variable 'use', welche sich in meiner Zählerklasse befindet.
Doch es läuft nicht
-
Doch, der Kopierkonstruktor wird dreimal aufgerufen, nämlich wenn S, Z und U aus main in die Parameter der Funktion tellme kopiert werden. Aber die Frage steht weiterhin, unabhängig ob der Kopierkonstruktor benutzt wird: Warum inkrementierst Du den Zeiger i_point?
Darüberhinaus, wieso muss die Ausgabe zu dem Zeitpunkt "0" sein? Das wäre doch schlicht gelogen, da ja der Smartpointer Z zu dem Zeitpunkt nach seinem Usecount gefragt wird, und damit zweifellos existiert und auf ein Objekt zeigt. Meiner Meinung nach macht der Code bis auf den erwähnten Copy-Ctor (der zu einem Double-Free am Ende von main führt) alles richtig. Auf Exception-Sicherheit o.ä. gehe ich dabei aber noch nicht ein.
-
Der Copy-Konstruktor wird schon alleine dann aufgerufen, wenn du tellme aufrufst, da du diesem keine Referenz übergibst.
EDIT: zu lange gelesen.

-
dumme frage:
sollten smartpointer nicht eigentlich dazu da sein, das ganze new und delete auch weg zu lassen? das sollte doch implizit in der hülle des smartpointer objektes geschehen und der anwender sollte doch (meines wissens nach) nichts damit zu tun haben. dachte smartpointer sind im endeffekt keine pointer, sondern eher lokale objekte, welche z.b. den operator -> überladen haben, um an den inhalt des objektes an sich zu kommen, aber ich kann mich, natürlich, auch täuschen
-
Nunja, das new kann Dir niemand abnehmen, da dafür der Smartpointer die Signatur aller möglichen Konstruktoren abbilden müsste (was natürlich mit etwas Aufwand auch möglich, aber m.M.n. nicht praktikabel ist). Stattdessen übergibt man dem Smartpointer üblicherweise direkt das Ergebnis des new-Ausdrucks, so dass man selbst den nackten Zeiger nie "in den Händen" (sprich in einer Variablen) hält. Das delete (oder Custom-Delete) übernimmt dann der Smartpointer.
{ smart_ptr<Typ> x( new Typ( /* hier Argumente einsetzen */ ) ); /* x benutzen, herumreichen, zuweisen, verfallen lassen */ } /* x stirbt, und wenn kein weiterer Verweis auf das Ergebnis unseres "new Typ" existiert, wird das Objekt dabei gelöscht */
-
Oh ihr habt recht.
Der Kopierkonstruktor wird tatsächlich 3 mal aufgerufen.
Zudem habe ich den Fehler, dass i_point incrementiert wird schon behoben.
Es muss natürlich use incrementiert werden!Nun lautet die Ausgabe:
Es gibt 4 Objekte. Es gibt 4 Objekte. Es gibt 2 Objekte.Erst erstelle ich S/Z/U es gibt also von jedem Objekt genau 1.
Danach weise ich Z = S zu.
Es müsste also nun zweimal S und 0 Mal Z geben.
Dann kopiere ich die Objekte in die Funktion und es müsste nun 3 Objekte von Z geben, null von S und zwei von U.Es gibt 0 Objekte. Es gibt 3 Objekte. Es gibt 2 Objekte.Doch nur für U stimmt das ganze...-.-

welche z.b. den operator -> überladen haben
Den kann man doch garnicht überladen?
-
joar, naja, überzeugt

aber, wenn man z.b. einen allocator angeben würde, wäre es möglich, dass das allokieren im Konstruktor des Smartpointers implizit geschieht
-
777 schrieb:
Erst erstelle ich S/Z/U es gibt also von jedem Objekt genau 1.
Danach weise ich Z = S zu.
Es müsste also nun zweimal S und 0 Mal Z geben.Etwas, was nicht existiert, kannst Du auch nicht nach seiner Existenz fragen. S und Z zeigen nach der Zuweisung auf dasselbe Objekt. Logischerweise haben auch beide Smartpointer den selben Usecount. Das Objekt, auf das Z mal gezeigt hat, ist weg.
777 schrieb:
welche z.b. den operator -> überladen haben
Den kann man doch garnicht überladen?
Doch, kann man. Schau Dir mal die Smartpointer der Standardbibliothek an.
-
Tatsächlich:
Das erste bei der Erstellung von S.
Das zweite, bei der Zuweisung von Z zu S.
Das dritte beim kopieren von S und das vierte beim kopieren von Z (was ja S ist)
THX
cya
David