Frage bezueglich SmartPointer



  • Guten Abend,

    vorab ich benutze Visual Studio 2010

    ich hab ein paar Dlls die mir per Factory function Objekte einer Klasse erstellen.
    Interface von denn alle erstellten Klassen erben:

    class dataBase
    {
    public:
    	virtual ~dataBase() {};
    	virtual void deleteSelf() = 0;
    };
    

    Um mich jetzt nicht um das Aufrauemen der Objekte kuemmer zu muessen hab ich mir eine kleine Hilfsfunktion gebaut die aus den Pointer einen beliebigen Smart Pointer erstellen soll.

    template< template <typename> class smart, typename T>
    smart< T > makeSmartPtr( T* data ) {
    
    	return smart< T >( data, boost::bind( &(T::deleteSelf), data) );
    
    }
    

    Diese hat auch mit den std::shared_ptr wunderbar geklappt. Jetzt wollt ich vorhin aber einen std::unique_ptr verwenden und da sagt er das geht ned.

    error C3208: 'module::helper::makeSmartPtr': Vorlagenparameterliste für Klassenvorlage 'std::unique_ptr' stimmt nicht mit der Vorlagenparameterliste für den template template-parameter 'smart' überein
    

    Dann hab ich mir mal die beiden Klassen angeguckt und siehe da std::unique_ptr hat 2 template Parameter und std::shared_ptr nur einen aber dafuer nen ueberladenen Konstruktor:

    std::unique_ptr

    // TEMPLATE CLASS unique_ptr SCALAR
    template<class _Ty,
    	class _Dx>	// = default_delete<_Ty>
    	class unique_ptr
    		: public _Unique_ptr_base<_Ty, _Dx,
    			tr1::is_empty<_Dx>::value
    				|| tr1::is_same<default_delete<_Ty>, _Dx>::value>
    	{
    

    std::shared_ptr

    // TEMPLATE CLASS shared_ptr
    template<class _Ty>
    	class shared_ptr
    		: public _Ptr_base<_Ty>
    	{	// class for reference counted resource management
    public:
    	typedef shared_ptr<_Ty> _Myt;
    	typedef _Ptr_base<_Ty> _Mybase;
    
    	template<class _Ux,
    		class _Dx>
    		shared_ptr(_Ux *_Px, _Dx _Dt)
    		{	// construct with _Px, deleter
    		_Resetp(_Px, _Dt);
    		}
    

    Jetzt zur Frage: ist das so gewollt und in allen implementationen so und wenn ja warum ist das nicht einheitlich?
    Und wie koennt ich das dann loesen?

    Gruessle



  • C0de4Fun schrieb:

    Jetzt zur Frage: ist das so gewollt und in allen implementationen so und wenn ja warum ist das nicht einheitlich?

    Hat mit Effizienz zu tun. unique_ptr soll nichts kosten, also ist der Deleter einfach sein Element. Dafür muss der Typ bekannt sein. shared_ptr fordert ohnehin dynamisch Speicher an, also muss der Deleter-Typ nicht vor dem Konstruktoraufruf bekannt sein.

    C0de4Fun schrieb:

    Und wie koennt ich das dann loesen?

    Warum benutzt du nicht einfach den Destruktor / Default Deleter?

    Eine Lösung wäre std::unique_ptr<T, std::function<void (T *)>> , um den genauen Typ des Deleters zu verstecken. boost::function geht natürlich auch.

    Ach ja: Der Deleter muss den zu löschenden Zeiger nicht kennen, er bekommt ihn vom Smart Ptr mitgeteilt, wenn es soweit ist.
    Vergleich:

    return smart< T >( data, boost::bind( &(T::deleteSelf), data) ); 
    return smart< T >( data, boost::bind( &(T::deleteSelf), _1) );
    

    Mit meinem Vorschlag:

    return std::unique_ptr<T, boost::function<void (T *)>>( data, boost::bind( &T::deleteSelf, _1) );
    


  • TyRoXx schrieb:

    Warum benutzt du nicht einfach den Destruktor / Default Deleter?

    Wie versteh ich nicht. Wenn ich das deleteSelf aufrufe wird doch der Destruktor aufgerufen.
    Und des Problem mit dem Default Deleter ist, dass ich ja die Sachen in einer Dll erstelle und im Programm verwenden will. Wenn ich jetzt dann spaeter das Object loeschen will und das delete vom Programm aufruf krachts da anderes Memory Management usw.

    TyRoXx schrieb:

    Eine Lösung wäre std::unique_ptr<T, std::function<void (T *)>> , um den genauen Typ des Deleters zu verstecken. boost::function geht natürlich auch.

    Ach ja: Der Deleter muss den zu löschenden Zeiger nicht kennen, er bekommt ihn vom Smart Ptr mitgeteilt, wenn es soweit ist.
    Vergleich:

    return smart< T >( data, boost::bind( &(T::deleteSelf), data) ); 
    return smart< T >( data, boost::bind( &(T::deleteSelf), _1) );
    

    Mit meinem Vorschlag:

    return std::unique_ptr<T, boost::function<void (T *)>>( data, boost::bind( &T::deleteSelf, _1) );
    

    Aber damit kann ich doch nicht eine Funktion haben dir mir einmal einen unique_ptr zurueck gibt und einmal eine shared_ptr oder?

    z.B:

    std::shared_ptr<hashApi> hash = makeSmartPtr<std::shared_ptr>( dllInterface->queryApi(HASH_ID));
    std::unique_ptr<keyManagerApi> keyManager = makeSmartPointer<std::unique_ptr>(dllInterface->queryApi(KEYMANAGER_ID));
    

    Oder seh ich das falsch?
    Das mit den ganzen Template verwirrt mich einfach zu sehr 😞



  • Warum nicht separate Funktionsüberladungen für std::shared_ptr und std::unique_ptr ?



  • Nexus schrieb:

    Warum nicht separate Funktionsüberladungen für std::shared_ptr und std::unique_ptr ?

    Also statt mit dem Template Parametern einfach zwei Funktionen ala:

    template<typename T>
    std::unique_ptr<T> makeSmartPtr(T* data) {
       return std::unique_ptr<T>( data, std::bind( &(T::deleteSelf), _1) );
    }
    
    template<typename T>
    std::shared_ptr<T> makeSmartPtr(T* data) {
       return std::shared_ptr<T>( data, std::bind( &(T::deleteSelf), _1) );
    }
    

    Aber ich dachte Funktionen duerfen sich nicht nur in ihrem return value unterscheiden oder verwechsel ich da grad was?



  • Sorry, ich meinte natürlich "separate Funktionen", also keine Überladung.



  • Nexus schrieb:

    Sorry, ich meinte natürlich "separate Funktionen", also keine Überladung.

    Ah ok. Joa dann werd ichs wohl so machen. Dacht mir halt nur sich das anbietet und alle smart Pointer das gleiche Interface haben.

    Aber dann danke derweil an euch beide und Gruessle


Anmelden zum Antworten