Kleine Smartpointer Fragen
-
Abend!
Ich beschäftige mich seit gestern mit Smart Pointern und habe dementsprechend einige kleine Fragen:
1. Sehe ich das richtig, dass man es "Intrusion Smart Pointer" nennt, wenn das Objekt, auf das der Smart Pointer zeigt, den Referenzzähler selber mitbringt? Das ist die effizienteste Form von Reference Counting, oder?
2. Ich habe im Netz Code für so ein "Intrusive" System gefunden. Da gab es eine Klasse Object, die hatte einen "int references" und jede andere Klasse leitete von Object ab. Was ich nicht verstehe: Der Ctor von Object setzte references auf 0. Sollte er references nicht auf 1 setzen? (wenn das Objekt erzeugt wird, gibt es ja ein "Ding")
3. Ich habe mir einige Smart Pointer angeschaut und die meisten hatten einen explicit Constructor. Aber dadurch wird doch sowas unmöglich:
SmartPtr<Foo> ptr = new Foo; // Geht nicht void method(SmartPtr<Foo> f); method(new Foo); // Geth auch nichtWieso macht man das dann? (also den Ctor explicit)
4. Sollte ich bei Parametern nur noch den Smart Pointer by value übergeben? (also void method(Smartptr<Foo> f); statt void method(Smartptr<Foo>& f))
Wann sollte ich by reference übergeben?
Und gibt es zwischen diesen 2 Aufrufen einen Unterschied?:Foo* methodA() { return new Foo; } SmartPtr<Foo> ptr = methodA(); SmartPtr<Foo> methodA() { return SmartPtr<Foo>(new Foo); } SmartPtr<Foo> ptr = methodA();Ist das nicht das selbe?
Danke!
-
huntelaar@vfb schrieb:
1. Sehe ich das richtig, dass man es "Intrusion Smart Pointer" nennt, wenn das Objekt, auf das der Smart Pointer zeigt, den Referenzzähler selber mitbringt? Das ist die effizienteste Form von Reference Counting, oder?
Ich nenne es eher intrusive smart pointers. Also eher "ja". Ich denke auch, daß es die effizienteste Form des Refcountings ist.
2. Ich habe im Netz Code für so ein "Intrusive" System gefunden. Da gab es eine Klasse Object, die hatte einen "int references" und jede andere Klasse leitete von Object ab. Was ich nicht verstehe: Der Ctor von Object setzte references auf 0. Sollte er references nicht auf 1 setzen? (wenn das Objekt erzeugt wird, gibt es ja ein "Ding")
Hängt von der Implementierung ab. in references kann ja per Definition immer eins weniger stehen sollen.
3. Ich habe mir einige Smart Pointer angeschaut und die meisten hatten einen explicit Constructor. Aber dadurch wird doch sowas unmöglich:
SmartPtr<Foo> ptr = new Foo; // Geht nicht void method(SmartPtr<Foo> f); method(new Foo); // Geth auch nichtWieso macht man das dann? (also den Ctor explicit)
Kein Ahnung. Geht SmartPtr<Foo> ptr(new Foo);?
4. Sollte ich bei Parametern nur noch den Smart Pointer by value übergeben? (also void method(Smartptr<Foo> f); statt void method(Smartptr<Foo>& f))
Natürlich nicht. Das würde ja Inkrementierungen, Dekrementierungen und ifs bedeuten. Du sollst normalerweise normale Objektreferenzen übergeben, smart pointers doch nur, wenn der Erzeuger nicht der Besitzer bleiben will.
Wann sollte ich by reference übergeben?
Wenn Du den Beitzt gar nicht aufgibst. Aber ich weiß nicht, ob es sinnvoll sein kann, einen smart pointer per ref zu übergeben. Ja, schon, wenn die funktion das Objekt evtl löschen will, aber anderenfalls der Besitzt beim AUfrufer bleibt. Könnte sein.
Und gibt es zwischen diesen 2 Aufrufen einen Unterschied?:
Foo* methodA() { return new Foo; } SmartPtr<Foo> ptr = methodA(); SmartPtr<Foo> methodA() { return SmartPtr<Foo>(new Foo); } SmartPtr<Foo> ptr = methodA();Ist das nicht das selbe?
[/quote]
Jo.
-
volkard schrieb:
Hängt von der Implementierung ab. in references kann ja per Definition immer eins weniger stehen sollen.
Ja, ne. references bedeutet schon die Anzahl der momentanen Referenzen.
Vielleicht hat es ja folgenden Sinn:
Der SmartPointer sieht so aus:SmartPtr<T>::SmartPtr(T* p) { if(p) { m_ptr = p; p->IncrementReferences(); } } Foo* f = new Foo; // ref == 0 SmartPtr<Foo> ptr = f; // ref == 1Wenn der Ctor von Object (Foo erbt von Object) den refcounter auf 1 setzen würde, dann wäre der zähler ja nach der zuweisung an den smart pointer 2. Is das der Grund, wieso so eine RefCounting Oberklasse zunächst den ref counter auf 0 setzt?
Wieso macht man das dann? (also den Ctor explicit)
Kein Ahnung. Geht SmartPtr<Foo> ptr(new Foo);?
Ja, das geht. Es geht sogar NUR so. Weiß sonst wer was für einen Sinn es macht, den Ctor SmartPtr<T>::SmartPtr(T* foo) explicit zu machen?
Du sollst normalerweise normale Objektreferenzen übergeben, smart pointers doch nur, wenn der Erzeuger nicht der Besitzer bleiben will.
Ja ok. Aber bei meinem Reference Counting SmartPtr wird ja nicht der Besitzer gewechselt. Es zeigt nur kurzzeitig noch ein weiterer auf das Objekt. Der Besitzer würde nur gewechselt werden bei einem Smart Pointer wie std::auto_ptr
Und gibt es zwischen diesen 2 Aufrufen einen Unterschied?:
Foo* methodA() { return new Foo; } SmartPtr<Foo> ptr = methodA(); SmartPtr<Foo> methodA() { return SmartPtr<Foo>(new Foo); } SmartPtr<Foo> ptr = methodA();Ist das nicht das selbe?
Jo.
Hm, wäre das dann ein gutes Design?: Ich habe eine Klasse Object, die hat eine Methode IncrementRefCount() und DecrementRefCount() sowie den ref counter.
In all meinen Factorymethoden gebe ich dann einen normalen Zeiger zurück:
Foo* create();Der Benutzer hätte dann jetzt 2 Möglichkeiten:
Manuelles Handeln:
Foo* f = create();
f->IncrementRefCount();
// benutze f
f->DecrementRefCount();oder automatisch:
SmartPtr<Foo> ptr = create();
// benutze ptrSehe ich das so richtig? Wäre das Design gut?
-
Bei expliziten Konstruktoren geht es meist um die Schadensbegrenzung. Implizite Konvertierungen finden manchmal statt, ohne dass der Programmierer damit rechnet. Man sollte sich also immer 2mal überlegen, ob ein impliziter Konstruktor nicht vielleicht mehr schadet als nutzt.
Beispiel:
void dings(shared_ptr<foo> p) { p->bums(); } int main() { foo* p = new foo; dings(p); // Das Objekt, auf das p zeigte gibt es nicht mehr!!! p->bums(); // U.B. delete p; // U.B. }Da so ein schlauer Zeiger die Verwaltung der Lebenszeit übernimmt -- ein roher Zeiger aber nicht -- kann die implizite Konvertierung schonmal ganz schön nach hinten losgehen.
Gruß,
SP
-
huntelaar@vfb schrieb:
volkard schrieb:
Hängt von der Implementierung ab. in references kann ja per Definition immer eins weniger stehen sollen.
Ja, ne. references bedeutet schon die Anzahl der momentanen Referenzen.
Vielleicht hat es ja folgenden Sinn:
Der SmartPointer sieht so aus:SmartPtr<T>::SmartPtr(T* p) { if(p) { m_ptr = p; p->IncrementReferences(); } } Foo* f = new Foo; // ref == 0 SmartPtr<Foo> ptr = f; // ref == 1Klar!
*mit dem Tisch an den Kopf hau*
-
huntelaar@vfb schrieb:
Abend!
1. Sehe ich das richtig, dass man es "Intrusion Smart Pointer" nennt, wenn das Objekt, auf das der Smart Pointer zeigt, den Referenzzähler selber mitbringt? Das ist die effizienteste Form von Reference Counting, oder?Man nennt das "intrusive reference counting".
huntelaar@vfb schrieb:
2. Ich habe im Netz Code für so ein "Intrusive" System gefunden. Da gab es eine Klasse Object, die hatte einen "int references" und jede andere Klasse leitete von Object ab. Was ich nicht verstehe: Der Ctor von Object setzte references auf 0. Sollte er references nicht auf 1 setzen? (wenn das Objekt erzeugt wird, gibt es ja ein "Ding")
Nö das passt schon. Solche Klassen verwenden man normalerweise so:
intrusive_ptr<T> p(new T); // ruft sofort add_ref() auf, womit der Zähler dann auf 1 stehtDadurch spart man sich Konstrukte mittels derer man dem Smart-Pointer mitteilt, dass er nicht add_ref() aufrufen soll.
huntelaar@vfb schrieb:
3. Ich habe mir einige Smart Pointer angeschaut und die meisten hatten einen explicit Constructor. Aber dadurch wird doch sowas unmöglich:
SmartPtr<Foo> ptr = new Foo; // Geht nicht void method(SmartPtr<Foo> f); method(new Foo); // Geth auch nichtWieso macht man das dann? (also den Ctor explicit)
Wurde ja schon beantwortet: um Fehler zu vermeiden.
huntelaar@vfb schrieb:
4. Sollte ich bei Parametern nur noch den Smart Pointer by value übergeben? (also void method(Smartptr<Foo> f); statt void method(Smartptr<Foo>& f))
Wann sollte ich by reference übergeben?Du solltest by const-ref übergeben. Das Kopieren eines smart-pointers ist oft einigermassen teuer, und sollte daher vermieden werden, wenn es nicht nötig ist.
By reference (ohne const) solltest du nur dann übergeben, wenn du den Zeiger ändern willst. Also als Output-Parameter verwenden. Und das sollte man der Übersichtlichkeit halber am besten vermeiden.huntelaar@vfb schrieb:
Und gibt es zwischen diesen 2 Aufrufen einen Unterschied?:
Foo* methodA() { return new Foo; } SmartPtr<Foo> ptr = methodA(); SmartPtr<Foo> methodA() { return SmartPtr<Foo>(new Foo); } SmartPtr<Foo> ptr = methodA();Ist das nicht das selbe?
Danke!
Nein, das ist nicht dasselbe. Das erste wird z.B. mit einem expliziten Konstruktor nicht funktionieren.