Makro vs. Funktion



  • Hallo Leute

    Weis ned ob das jetzt hier her oder ins WinAPI Forum gehört, aber ich denke, dass man das auch allgemein beantworten kann.
    Ich möchte folgendes Makro umschreiben als, von mir aus globale, Funktion:

    #define SAFE_RELEASE(p) { if(p) {(p)->Release(); (p)=NULL;} }
    

    Wobei p in der Regel ein Zeiger auf ein COM Object ist. (Wird zB in DirectX oft verwendet)
    Nun seh ich zwei mögliche Funktionen:

    //so
    safe_release( void* p ) {
        if( p != NULL ) {
            p->Release();
            p = NULL;
        }
    }     
    //oder so
    safe_release( IUnknown* p ) {
        if( p != NULL ) {
            p->Release();
            p = NULL;
        }
    }
    

    Ist das überhaupt sinnvoll?
    (Oder kommts mir nur so vor, weil ich keine Makros mag..)
    Und wenn ja, welche Version würdet ihr vorschlagen?

    Wäre um Hilfe und Meinungen froh 🙂

    mfg
    Mat



  • Eher so:

    template<typename Ptr>
    void safe_release(Ptr*& p) {
      if (p) {
         p->Release();
         p = 0;
      }
    }
    


  • Hi
    und Danke

    Hab grad gemerkt dass ich Unsinn geposted hab.
    Es geht natürlich nicht mit void,*
    denn das Objekt muss ja die virtuelle Methode Release() überschreiben.
    Da das ganze nur für COM Objekte benutzt würde, ist wohl die Basisklasse ausreichen,
    mit template wärs wohl etwas overdosed und der Aufruf entsprechend aufgeblasen

    safe_release( g_lpD3DDevice );
    vs.
    safe_release<LPD3DDEVICE>( g_lpD3DDevice );
    

    mfg
    Mat



  • Sorry fürs Doppelpost..

    Aber mit "keine Macht den Makros" lieg ich schon richtig oder?
    Und wo sollte ich die Funktion reinklatschen, in nen "globalen" Header,
    oder jeder Klasse, die COM Objekte ( IUnknown Derivate ) besitzt als Methode übergeben, bzw eine abstrakte Basisklasse zum Kapseln solcher Interfaces machen?



  • Stimmt nicht, Template-Funktionen können ihre Template-Parameter anhand der Parameter selbst ermitteln.

    Allerdings hast Du recht wenn Du sagst dass es über die Basisklasse genauso gut geht (dann vergiss aber nicht den Zeiger als Referenz (IUnknown*&) zu übergeben, sonst hat das p = NULL keinerlei Auswirkung).



  • Besser wäre es einfach boost::intrusive_pointer zu verwenden.



  • Ah so Danke.
    Hab bis jetzt nur Template-Klassen genutzt, keine Funktionen, von daher wusst ich das ned.
    Aber das mit der Zeiger-Referenz-Übergabe hab ich ganz übersehn. Ist aber im Nachhinein eindeutig klar.
    @DrProf: Was machen den die intrusive pointer?

    Also was ich im Endeffekt erreichen will, ist, das alle Objekte sauber aufgeräumt werden, egal, wie ich das Programm beende.
    Wärs da nicht schlau, eine Art "Mülleimer" zu machen, der als Member eine Liste der COM-Zeiger enthält, und im Destruktor alle mit safe_release(); freigibt?

    mfg
    Mat



  • Ein intrusive_ptr ist ein Smart-Pointer - der kümmert sich selber darum, daß er vor der Vernichtung noch den Speicher freigibt.

    (für genauere Erklärungen kannst du z.B. hier vorbeischauen)



  • Hey Danke

    Über den Artikel bin ich auf folgenden Artikel bei Codeproject gestossen:
    Kreativer Missbrauch von shared_ptr<T>
    Ganz interessant, aber doch etwas aufgebläht.
    Da versuch ich lieber das ganze sicher genug zu coden 😃

    Danke nochmal euch allen

    mfg
    Mat



  • das mit der referenz hab ich nicht gerafft. der wert (die adresse) wird doch normal ohne referenz einfach kopiert. steht das irgendwo im standard, dass das bei zeigern anders ist? folgender test hat NICHT ergeben, dass der zeiger-wert ohne benutzen einer referenz verändert wird:

    #include <iostream>
    using namespace std;
    
    template<typename T>
    inline bool isPointerNULL(T *ptr){ return ptr == 0; }
    
    int main()
    {
        int *test1 = 0;
        int test2;
        cout << isPointerNULL(test1) << endl;
        cout << isPointerNULL(&test2) << endl;
    }
    

    hat jemand ein beispiel, dass die notwendigkeit einer referenz unterstreicht?



  • sorry, hab nicht richtig gelesen. der pointer wird ja gesetzt...


Anmelden zum Antworten