[ownership]memory leaks



  • Ich habe eine funktion

    int func(int* i);
    

    Ist es moeglich, wenn die funktion wie folgt aufgerufen wird

    func(new int(42));
    

    und somit die ownership von dem new Ergebnis an die funktion transferiert wird, ein memory leak zu verhindern, wenn die funktion i nicht selbst deleted?



  • Nein.



  • mit smart pointern geht das, aber nicht mit normalen zeigern.



  • 0xdeadbeef schrieb:

    Nein.

    Doch, wenn func den Pointer zurückgibt.

    Bye, TGGC (Wähle deine Helden)



  • TGGC schrieb:

    0xdeadbeef schrieb:

    Nein.

    Doch, wenn func den Pointer zurückgibt.

    Was - as you can see - nicht der Fall ist.

    MfG SideWinder



  • Nein, kann man nicht sehen.

    Bye, TGGC (Wähle deine Helden)



  • TGGC schrieb:

    Nein, kann man nicht sehen.

    Also ich schon.

    Raptor schrieb:

    int func(int* i);
    

    🙂



  • groovemaster schrieb:

    TGGC schrieb:

    Nein, kann man nicht sehen.

    Also ich schon.

    Raptor schrieb:

    int func(int* i);
    

    🙂

    Er meint wohl den (Sonder-)Fall

    int func(int* i)
    {
      // ...
      return *i;
    }
    

    Macht aber trotzdem nicht allzuviel Sinn.



  • finix schrieb:

    groovemaster schrieb:

    TGGC schrieb:

    Nein, kann man nicht sehen.

    Also ich schon.

    Raptor schrieb:

    int func(int* i);
    

    🙂

    Er meint wohl den (Sonder-)Fall

    int func(int* i)
    {
      // ...
      return *i;
    }
    

    Verstehe ich nicht.
    Ich sehe nur eine Möglichkeit func so zu implementieren, dass TGGCs Posting sinn macht:

    int func(int* i)
    {
    return reinterpret_cast<int>(i);  
    }
    reinterpret_cast<int*> p = func(new int(22));
    delete p;
    

    Diese Implementation ist aber derart schwachsinnig, dass man eigentlich nur zum dem Schluss kommen kann, dass TGGCs Posting völlig sinnbefreit ist.



  • HumeSikkins schrieb:

    Verstehe ich nicht.

    Macht nichts. Ist bei genauerer Betrachtung in der Tat recht schwachsinnig, auch wenn es rein um die Möglichkeit, nicht um Sinn(haftigkeit) und Zweck ging.

    // int func(int* i);
    // wird zu
    int* func(int* i)
    {
      // ...
      return i;
    }
    

    Macht aber natürlich dann Sinn wenn der Rückgabe wert keinen Sinn macht (und man überhaupt Einfluss auf func hat).

    Darüber hinaus könnte man noch einen Wrapper nehmen:

    int* func_wrapper(int* i)
    {
      func(i);
      return i;
    }
    
    // oder wenn's nur darum geht die Funktion praktisch aufzurufen
    int func_wrapper(int* i)
    {
      int res = func(i);
      delete i;
      return res;
    }
    

    Auch albern, aber vielleicht ganz nett fuer Übergangslösungen und Wartungsalbträme:

    // func_wrapper.hpp
    namespace wrap_it {
      int func(int*);
    }
    
    // func_wrapper.cpp
    #include "func.hpp"
    
    namespace wrap_it {
      int func(int* i) {
        int res = ::func(i);
        delete i;
        return res;
      }
    }
    
    // client.cpp
    #ifdef USE_WRAPPER
    #include "func_wrapper.hpp"
    using wrap_it::func;
    #else
    #include "func.hpp"
    #endif
    


  • Ihr vergesst da noch eine Sache. Einen Zeiger in einem int zu "verstecken" ist ja unter einer typischen 32 Bit Platform möglich, aber was macht man, wenn's um Portabilität geht? ZB ist unter Win64 ein int 32 Bit (afaik), ein Zeiger aber 64 Bit. Also wird dann einfach abgeschnitten und wichtige Informationen gehen unwiederbringlich verloren. "Naja, dann nehmen wir halt long". Und auf der nächsten Plattform, die unterschiedliche long <-> Zeiger Datenbreiten aufweist, ändern wir wieder unseren ganzen Code. Sehr schön, darauf freut man sich doch. Besonders auf die anschliessende Fehlersuche. Naja, dazu kann ich eigentlich nur nochmal Hume zitieren

    HumeSikkins schrieb:

    Diese Implementation ist aber derart schwachsinnig

    Wenn man schon einen Zeiger in einem Ganzzahltyp halten will (zB für arithmetische Berechnungen), dann sollte man imo einen eigenen Typ verwenden (wie zB INT_PTR in WinAPI), der je nach Plattform angepasst wird.



  • Ich glaube es ging hier wohl keinem der beitiligten um einen reellen Sinn, sondern einfach nur um die theoretische Möglichkeit;)



  • groovemaster schrieb:

    Wenn man schon einen Zeiger in einem Ganzzahltyp halten will (zB für arithmetische Berechnungen), dann sollte man imo einen eigenen Typ verwenden (wie zB INT_PTR in WinAPI), der je nach Plattform angepasst wird.

    war size_t nicht genau dafür gedacht?


  • Mod

    otze schrieb:

    groovemaster schrieb:

    Wenn man schon einen Zeiger in einem Ganzzahltyp halten will (zB für arithmetische Berechnungen), dann sollte man imo einen eigenen Typ verwenden (wie zB INT_PTR in WinAPI), der je nach Plattform angepasst wird.

    war size_t nicht genau dafür gedacht?

    wenn ich den standard richtig lese, dann nein. ich denke da an ms-dos, medium memory model
    kein einziger typ (also auch arrays) kann hier grösser als 64KB sein, also genügt es, wenn size_t 16bit hat - trotzdem sind pointer hier 4 byte gross, da ja mehrere segmente zur verfügung stehen.



  • otze schrieb:

    groovemaster schrieb:

    Wenn man schon einen Zeiger in einem Ganzzahltyp halten will (zB für arithmetische Berechnungen), dann sollte man imo einen eigenen Typ verwenden (wie zB INT_PTR in WinAPI), der je nach Plattform angepasst wird.

    war size_t nicht genau dafür gedacht?

    Für das Halten von Zeigeradressen? Nein.

    MfG SideWinder



  • otze schrieb:

    groovemaster schrieb:

    Wenn man schon einen Zeiger in einem Ganzzahltyp halten will (zB für arithmetische Berechnungen), dann sollte man imo einen eigenen Typ verwenden (wie zB INT_PTR in WinAPI), der je nach Plattform angepasst wird.

    war size_t nicht genau dafür gedacht?

    AFAIK nicht. size_t ist als vorzeichenloser Ganzzahltyp definiert, welcher vom sizeof Operator zurückgegeben wird. Insofern ist size_t dann angebracht, wenn es um Grössen oder Offsets von Speicherbereichen geht.

    camper schrieb:

    ich denke da an ms-dos, medium memory model
    kein einziger typ (also auch arrays) kann hier grösser als 64KB sein, also genügt es, wenn size_t 16bit hat - trotzdem sind pointer hier 4 byte gross

    Ist das beim medium memory model so?
    Ich dachte, unter DOS unterscheidet man generell zwischen near und far Zeigern. Near Zeiger beinhalten nur den Offset Anteil des aktuellen Segments, sind also 16 Bit. Far Zeiger beinhalten Offset und Segment, sind also 32 Bit.



  • groovemaster schrieb:

    otze schrieb:

    groovemaster schrieb:

    Wenn man schon einen Zeiger in einem Ganzzahltyp halten will (zB für arithmetische Berechnungen), dann sollte man imo einen eigenen Typ verwenden (wie zB INT_PTR in WinAPI), der je nach Plattform angepasst wird.

    war size_t nicht genau dafür gedacht?

    AFAIK nicht. size_t ist als vorzeichenloser Ganzzahltyp definiert, welcher vom sizeof Operator zurückgegeben wird. Insofern ist size_t dann angebracht, wenn es um Grössen oder Offsets von Speicherbereichen geht.

    richtig, davon bin ich auch ausgegangen, hab dann wohl falsch weitergedacht 😕

    ich meine,was für einen sinn hat es, wenn man mit einem size_t ein array >addressierbarer speicher darstellen kann. genauso unlogisch ist es meiner meinung, wenn ein char[size_t(-1)] kleiner als der speicherbereich ist, der addressierbar ist. Daraus folgerte ich halt dann: size_t ist so groß, wie der speicher den das system maximal zur verfügung stellen kann.


  • Mod

    groovemaster schrieb:

    Ist das beim medium memory model so?
    Ich dachte, unter DOS unterscheidet man generell zwischen near und far Zeigern. Near Zeiger beinhalten nur den Offset Anteil des aktuellen Segments, sind also 16 Bit. Far Zeiger beinhalten Offset und Segment, sind also 32 Bit.

    im prinzip schon, nur ist das ja kein standard - für den sind ja alle datenpointer gleich in dem sinne, dass man sie sicher nach void* und zurück casten kann. deshalb gibt es diese speichermodelle ja - jedes modell bedingt gewisse einschränkungen, die den default-pointertyp beeinflussen. und für medium und grössere modelle sind eben mehrere datensegmente vorgesehen, so dass datenpointer dann eben 4 byte brauchen.

    ich meine,was für einen sinn hat es, wenn man mit einem size_t ein array >addressierbarer speicher darstellen kann. genauso unlogisch ist es meiner meinung, wenn ein char[size_t(-1)] kleiner als der speicherbereich ist, der addressierbar ist. Daraus folgerte ich halt dann: size_t ist so groß, wie der speicher den das system maximal zur verfügung stellen kann.

    und genau letzteres ist eben nicht sinnlos - segmentierte adressierung bringt eine vielzahl von konzepten, die ansonsten sehr simpel wären, durcheinander. bei segmentierter addressierung kann ich eben nicht den gesamten speicher linear durchlaufen, sondern immer nur stücke davon - auf grund der anforderungen, die C an die pointerarithmetik in arrays stellt, heisst das aber, dass ein einzelnes array (und damit jeder datentyp) nicht grösser als ein segment sein kann. das ist auch der grund, warum es keine portable (standardisierte sowieso nicht) methode gibt, um pointer für beliebige datentypen korrekt auszurichten.

    es gibt im übrigen eine vielzahl von systemen, bei denen der adressierbare speicher zwar von der grösse 2^n ist, aber n eben nicht ein vielfaches eines bytes ist, so dass es - wenn man die bedingung stellte, dass size_t genau den bereich darstellt, den man adressieren kann - evtl. gar keinen fundamentalen integralen typ gibt, der size_t entspricht.


Log in to reply