Template: Methode als Templateparameter angeben



  • Hallo,

    weiß jmd von euch wie ich bei meinem Template den Destruktor generalisieren kann?

    Ich möchte COM Objekte in den ScopedPtr packen können, die im Destructor abgebaut werden - durch den Aufruf "ptr->release() wie im Code dargestellt; gleichzeitig soll der Destruktor aber auch Objekte abbauen können, die beispielsweise ein "delete" benötigen.

    Wie kann ein solcher zweiter Templateparameter aussehen?

    template <typename T>
    class ScopedPtr
    {
    public:
    	ScopedPtr(T* _ptr) : ptr(_ptr) {}
    
    private:
    	ScopedPtr() : ptr(nullptr) {}
    	~ScopedPtr();
    
    private:
    	T* ptr = nullptr;
    };
    
    template <typename T>
    ADelPtr<T>::~ADelPtr()
    {
    	if (ptr)
    		ptr->release(); 
    }
    

    BTW: Das Template ist nicht vollständig, sondern auf das notwendigste reduziert.

    VG
    Jens



  • Wieso verwendest du nicht unique_ptr? Er hat für diesen Zweck den Deleter-Typen (oder per Default std::default_delete).



  • Jodocus schrieb:

    Wieso verwendest du nicht unique_ptr? Er hat für diesen Zweck den Deleter-Typen (oder per Default std::default_delete).

    Das stimmt, dieser funktioniert aber nicht mit den COM Objekten.



  • Warum sollte er nicht?
    Aus dem Kopf getippt, Fehler sind zur Übung. 😉

    namespace detail {
        template<typename T>
        void release(T* ptr) {
            ptr->release();
        }
    }
    
    template<typename T>
    using ReleasePtr = std::unique_ptr<T, void(*)(T*)>;
    
    template<typename T>
    ReleasePtr<T> makeReleasePtr(T* ptr) {
        return ReleasePtr(ptr, &detail::release<T>);
    }
    
    ReleasePtr<Foo> ptr = makeReleasePtr(createFoo());
    ptr->bar();
    


  • Das verbraucht weniger Speicher und ist einfacher zu benutzen:

    namespace detail
    {
        struct ReleaseDeleter
        {
            template<typename T>
            void operator()(T* ptr) const
            {
                ptr->release();
            }
        };
    }
    
    template<typename T>
    using ReleasePtr = std::unique_ptr<T, detail::ReleaseDeleter>;
    
    template<typename T>
    ReleasePtr<T> makeReleasePtr(T* ptr)
    {
        return ReleasePtr(ptr);
    }
    
    ReleasePtr<Foo> ptr = makeReleasePtr(createFoo());
    ptr->bar();
    


  • Weniger Speicher? Ich denke, der unique_ptr legt da ein Objekt deines Deleters per Default Konstruktor an, ein bisschen Speicherverschwendung hast du wohl immer. 😉



  • Ethon schrieb:

    Weniger Speicher? Ich denke, der unique_ptr legt da ein Objekt deines Deleters per Default Konstruktor an, ein bisschen Speicherverschwendung hast du wohl immer. 😉

    Nein, das Objekt braucht durch Empty Base Optimization keinen zusätzlichen Platz.

    Das ist übrigens einer der Gründe, warum unique_ptr einen Template-Parameter für den Deleter hat und nicht einfach einen Funktionszeiger benutzt. Der Default-Deleter mit delete ist auch ein struct , kein Zeiger.



  • Noch ein Hinweis: Die C++-Bibliothek der Windows Runtime beinhaltet bereits einen Smart Pointer für COM-Objekte, der auch noch ein paar zusätzliche COM-spezfische Methoden kennt:

    https://msdn.microsoft.com/en-us/library/br244983.aspx

    Vielleicht hilft das weiter.


Log in to reply