SharedPtr<Base> mit "Derived" class
-
Hi, wer kann mir sagen warum der folgende Code mit dem "std::shared_ptr" functioniert, nicht aber mit dem Minimal-Beispiel der "SharedPtr"-Klasse? Welchen Konstructor von hier http://de.cppreference.com/w/cpp/memory/shared_ptr/shared_ptr muss ich denn noch implementieren?
#include <memory> #include <iostream> template <class T> class SharedPtr { public: SharedPtr(); SharedPtr(const SharedPtr<T>& value); SharedPtr(T* p); ~SharedPtr(); template <class U> SharedPtr<T>::SharedPtr(const SharedPtr<U>& value) : _value(static_cast<value._value>) { } T* operator->() const; operator T*() const; private: T* value; }; template <class T> SharedPtr<T>::SharedPtr() { } template <class T> SharedPtr<T>::SharedPtr(const SharedPtr<T>& value) : value(value.value) { } template <class T> SharedPtr<T>::SharedPtr(T* value) : value(value) { } template <class T> SharedPtr<T>::~SharedPtr() { } template <class T> T* SharedPtr<T>::operator->() const { return _value; } template <class T> SharedPtr<T>::operator T*() const { return value; } class Base { public: void Test1(); void Test2(); }; void Base::Test1() { std::wcout << L"Test1\n"; } void Base::Test2() { std::wcout << L"Test2\n"; } class Derived : public Base { }; void Test1(std::shared_ptr<Base> test) { if (test) { test->Test1(); } } void Test2(SharedPtr<Base> test) { if (test) { test->Test2(); } } int main() { std::shared_ptr<Derived> derived1(new Derived()); Test1(derived1); SharedPtr<Derived> derived2(new Derived()); Test2(derived2); std::cin.get(); return 0; }
-
error C2664: 'Test2': Konvertierung des Parameters 1 von 'SharedPtr<T>' in 'SharedPtr<T>' nicht möglich.
-
Sieht gut aus, das was du benötigst steckt hier drin:
template <class U> SharedPtr<T>::SharedPtr(const SharedPtr<U>& value) : _value(static_cast<value._value>) { }Das SharedPtr<T>:: ist falsch und ein static_cast brauchst du auch nicht, vielleicht ein check ob T Basisklasse von U ist.
-
Aber wieso willst du deinen eigenen shared_ptr schreiben?
Entweder den std shared_ptr oder den aus Boost...
-
Was soll das werden? Ein Zeigers, der nichts mehr löscht?
Und was soll
void Test2(SharedPtr<Base> test)sein?
ÜBERGEBE NIE SMARTPOINTER ALS ARGUMENT (wenn du nicht weisst, was du tust)!
Das sollte
void Test2(Base const& test)sein und dann ist dein Problem gelöst.
-
sharry schrieb:
Und was soll
void Test2(SharedPtr<Base> test)sein?
ÜBERGEBE NIE SMARTPOINTER ALS ARGUMENT (wenn du nicht weisst, was du tust)!
Aha. ok. Dann tun wir halt alle immer so, als wüssten wir, was wir machen.
Und jetzt?Will sagen, keine Behauptungen oder Anweisungen oder Argument!
Was ist so schlimm an einer shared_ptr Kopie? Uuuh, langsam?
Ich mein, der shared_ptr ist ja gerade dafür da, dass er kopiert werden kann.
-
ptr^^ schrieb:
Was ist so schlimm an einer shared_ptr Kopie? Uuuh, langsam?
Nein, es ist eine unnötige Einschränkung, dass man die Funktion nur mit shared_ptr aufrufen kann.
Ist oft zu sehen, dass manche Leute mit shared_ptr programmieren, weil sie denken, das wäre gerade cool und dann Funktionen schreiben, die shared_ptrs annehmen, obwohl eigentlich eine Referenz ausgereicht hätte. Das führt dazu, dass shared_ptrs auch an Stellen benutzt werden müssen, wo sie gar nicht gebraucht werden und das führt zu einem verkackten Design das auch noch langsam ist.
Wenn die Funktion irgendwo eine Kopie speichert, dann ist eine const-Referenz auf einen shared_ptr grundsätzlich in Ordnung. Sollte aber so ziemlich nie der Fall sein (globale Funktionen die was speichern implizieren global State -> nie eine gute Idee).
-
@ptr^^
Ich schreibe keinen SharedPtr, das ist nur ein Beispiel. Ich schreibe einen "CustomPtr" da es für mein Problem keinen geeigneten SmartPtr gibt und das Konzept der SmartPointer von std und boost einfach Schrott ist.@sharry
Ach Leute, wieso müsst ihr immer Dinge in den Raum werfen die gar nicht zur Diskussion stehen. Das war nur ein Minimal-Beispiel um das Problem aufzuzeigen, hatte ich aber auch geschrieben. Und wie du per Referenz einen nullptr übergeben willst musst die mir jetzt noch erklären.
Und einen SharedPtr als rohen Pointer zu übergeben ist ja wohl total bescheuert. Denn dann hat der SharedPtr womöglich das Objekt gelöscht und man übergibt einen dangling Pointer. Super.
Evtl. könnte man den SharedPtr als const Ref übergeben, aber bin mir nicht sicher ob das nicht auch wieder problematisch ist.
-
@KasF
Hi danke für deinen Tipp, funktioniert aber leider auch nicht:template <class U> SharedPtr::SharedPtr(const SharedPtr<U>& value) : _value(value._value) { }
-
Enumerator schrieb:
Denn dann hat der SharedPtr womöglich das Objekt gelöscht und man übergibt einen dangling Pointer.
Solange die Methode nicht nebenläufig aufgerufen wird, kann es nicht sein, dass der SharedPtr das Objekt löscht.
Enumerator schrieb:
Evtl. könnte man den SharedPtr als const Ref übergeben, aber bin mir nicht sicher ob das nicht auch wieder problematisch ist.
Wie oben: solange du dich im selben Thread befindest, absolut unproblematisch. Falls die Klasse, zu der die Methode gehört, den Pointer speichern soll, legt sie sich eine Kopie an - unabhängig davon, ob der Pointer vorher als Referenz reingegeben wurde oder per Value (also bereits kopiert ist).
-
Ah, stand auf dem Schlauch. So gehts:
template <class U> SharedPtr(const SharedPtr<U>& value) : value(value) { }Und wie schreibe ich das ganze nun außerhalb der SharedPtr-Klasse?
So gehts nicht:template <class T> template <class U> SharedPtr<T>::SharedPtr(const SharedPtr<U>& value) : value(value) { }
-
Enumerator schrieb:
@KasF
Hi danke für deinen Tipp, funktioniert aber leider auch nicht:template <class U> SharedPtr::SharedPtr(const SharedPtr<U>& value) : _value(value._value) { }Das SharedPtr:: muss weg. Du schreibst bei den anderen Methoden und Konstruktoren in der Klassen ja auch kein SharedPtr davor.
-
daddy_felix schrieb:
solange du dich im selben Thread befindest, absolut unproblematisch.
Das ist absolut unproblematisch. Deine beschriebenen Fälle sind nur mit Fehlanwendungen von Threading möglich, da liegt der Fehler aber nicht bei der Funktion.
Enumerator schrieb:
Und einen SharedPtr als rohen Pointer zu übergeben ist ja wohl total bescheuert. Denn dann hat der SharedPtr womöglich das Objekt gelöscht und man übergibt einen dangling Pointer. Super.
Evtl. könnte man den SharedPtr als const Ref übergeben, aber bin mir nicht sicher ob das nicht auch wieder problematisch ist.Wie ich Leute hasse, die C++ nicht verstehen und überall Fehlerquellen sehen, gegen die sie sich mehrfach absichern müssen. Hat sogar einen Namen: Cargo cult programming.
Ich verstehe zwar nicht, wozu man erlauben möchte, dass das Argument ein nullptr ist, aber
void Test1(Base const& test); void Test2(Base const* test); shared_ptr<Base> b = ... Test1(*b); // 100% sicher, kein Fehler denkbar Test2(b.get()); // 100% sicher, kein Fehler denkbarist immer korrekt.
-
Enumerator schrieb:
Ah, stand auf dem Schlauch. So gehts:
template <class U> SharedPtr(const SharedPtr<U>& value) : value(value) { }Und wie schreibe ich das ganze nun außerhalb der SharedPtr-Klasse?
So gehts nicht:template <class T> template <class U> SharedPtr<T>::SharedPtr(const SharedPtr<U>& value) : value(value) { }// Deklaration in Klasse template <class U> SharedPtr(const SharedPtr<U>& value); // Definition außerhalb template<typename T> template<typename U> SharedPtr<T>::SharedPtr(const SharedPtr<U> &value) : _value(value._value) { }
-
@Sherry
Die tatsächliche Funktion heißt aber nicht Test sondern Add und fügt den SharedPtr einer Liste hinzu. Würde ich nur den rohen Zeiger nehmen. Wäre es also 100%tig falsch.
-
sharry schrieb:
void Test1(Base const& test); void Test2(Base const* test); shared_ptr<Base> b = ... Test1(*b); // 100% sicher, kein Fehler denkbar Test2(b.get()); // 100% sicher, kein Fehler denkbarist immer korrekt.
void Test2(Base const* test) { delete test; }
-
@KasF
Jetzt hatte ich vor lauter Hektik die Deklaration in der Klasse noch ausgeklammert gehabt. Super, funktioniert nun. Danke euch für die Hilfe.
-
Enumerator schrieb:
@ptr^^
Ich schreibe keinen SharedPtr, das ist nur ein Beispiel. Ich schreibe einen "CustomPtr" da es für mein Problem keinen geeigneten SmartPtr gibt und das Konzept der SmartPointer von std und boost einfach Schrott ist.Genauso klingt ein Kollege von mir. Und weisst du was? Oberflächlich denkt man, dass er weiss wovon er spricht. Aber er hat letztlich keine Ahnung. Und genau den Eindruck machst du auch, gerade durch solche schwachsinnigen Aussagen.
Ich denke du bist immer noch dran deine komische Baumstruktur mit Controls und was weiss ich darzustellen, richtig?
Dann erklär mal lieber, was du mit deinem "CustomPtr" vorhast, wie er funktionieren soll und wo er besser oder schlechter ist als shared_- oder unique_ptr.
-
Dafür liebe ich euch ;). Kaum geht man mal einen anderen Weg ist man der Böse. Ich habe ja wie du weißt ein wenig mit den Smartpointern rumexperimentiert und halt festgestellt, dass es für mein Problem keinen passenden gibt. Z.B. hätte ich das Problem von "Smart-Pointer-Kollisionen". Was machst du wenn du eine Liste von shared_ptrn hast aber nun auch einen Unique-Pointer oder Weak-Pointer ebenfalls darin speichern möchtest?
Die Lösung ist ganz einfach. Anstatt mehrerer SmartPointer-Typen gibt es bei mir nur einen. Diese können bei Bedarf mit einem Flag versehen werden, das angibt ob er Strong, Weak oder Unique ist. Da alle std Smart-Pointer sowieso mehr oder weniger nur eine Untermenge des shared_ptrs sind macht eine Trennung meiner Meinung nach eh keinen Sinn. Den Overhead durch den unnützen RefCounter-Pointer für z.B. einen WeakPointer nehme ich in kauf und denke es ist vertretbar.
Und das beste. Bislang integriert sich dieser Pointer wunderbar in mein Framework. Die std Smart-Pointer dagegen nicht. Wenn ihr mit diesen klar kommt bitte, aber ich habe für mich festgestellt, dass die std-Library für Standard-Sachen nett ist. Für spezielle Dinge aber eben nicht.
Und sei doch mal ehrlich. Diese Smart-Pointer-Geschichte ist doch eine einzige Krücke. Leider ist Kritik an der Std-Library scheinbar nicht erlaubt.
Schade, denn sonst würden im Jahr 2013 vielleicht auch schon so "extravagante" Dinge wie namespaces usw. Verwendung finden .
-
Kaum geht man mal einen anderen Weg ist man der Böse.
Wenn der "andere" Weg Blödsinn ist, dann schon, ja.
Was machst du wenn du eine Liste von shared_ptrn hast aber nun auch einen Unique-Pointer oder Weak-Pointer ebenfalls darin speichern möchtest?
Dann ist dein Design falsch, punkt. Entweder du brauchst eine Liste von
shared_ptroder nicht - wieso zum Teufel brauchst du Listen von verschiedenen Smart-Pointer-Typen?
Das ist als würde man sagen, man hat eine Liste vonvectors, und möchte jetzt einelisteinfügen. Das sind zwei verschiedene Dinge, auch wenn sie vielleicht ähnlich erscheinen.Die Lösung ist ganz einfach. Anstatt mehrerer SmartPointer-Typen gibt es bei mir nur einen. Diese können bei Bedarf mit einem Flag versehen werden, das angibt ob er Strong, Weak oder Unique ist.
Das ist ... so ein Blödsinn. Ich finde das lächerlich.
Da alle std Smart-Pointer sowieso mehr oder weniger nur eine Untermenge des shared_ptrs sind
Sind sie nicht! Wieso sollten sie das sein?
Den Overhead durch den unnützen RefCounter-Pointer für z.B. einen WeakPointer nehme ich in kauf und denke es ist vertretbar.
Nein, das ist er nicht.
Und sei doch mal ehrlich. Diese Smart-Pointer-Geschichte ist doch eine einzige Krücke.
Sei doch mal ehrlich, du hast keine verdammte Ahnung wovon du sprichst.
Und genau den Eindruck machst du auch, gerade durch solche schwachsinnigen Aussagen.
