Wie Speicher elegant wieder freigeben (bei Funktionsabbruch)?



  • Hallo,

    ich habe mehrere Funktionen, die hintereinander ausgeführt werden sollen. Falls eine dieser Funktionen fehlschlägt soll die Funktion nicht weiter ausgeführt werden, initialisierter Speicher aber freigegeben werden. Bisher sieht mein Konstrukt so aus:

    Aufruf()
    {
    reserviere Speicher1
    reserviere Speicher2

    if(!Funktion1(Speicher1, Speicher2)) {gebe Speicher1 frei; gebe Speicher2 frei; return false;}

    if(!Funktion2(Speicher1, Speicher2)) {gebe Speicher1 frei; gebe Speicher2 frei; return false;}

    if(!Funktion3(Speicher1, Speicher2)) {gebe Speicher1 frei; gebe Speicher2 frei; return false;}

    Hier kommt weiterer Code der nur ausgeführt werden soll, wenn alles vorher geklappt hat.

    gebe Speicher1 frei;
    gebe Speicher2 frei;

    return true;
    }

    Ich finde die Lösung nicht sehr elegant, da der selbe Code mehrfach vorhanden ist. Eine Verschachtelung mit if()s finde ich allerdings noch störender. Eine weiter Möglichkeit wäre ein success-flag. Dann müsste vor jeder Funktion geprüft werden, ob der Code bisher erfolgreich (successful) war. Man könnte auch eine Funktion schreiben, die den Speicher freigibt und vor dem Return ausgeführt wird.

    Wie würdet ihr das implementieren?

    Vielen Dank für eure Hilfe!

    Moritz



  • RAII



    • std::tr1::scoped_ptr
    • boost::scoped_ptr
    • std::auto_ptr

    , je nachdem was zur Verfügung steht.



  • Wozu musst du den Speicher überhaupt dynamisch anfordern? Zeig mal ein konkretes Besipiel wozu du

    reserviere Speicher1
    reserviere Speicher2
    

    brauchst.



  • brotbernd schrieb:

    Wozu musst du den Speicher überhaupt dynamisch anfordern? Zeig mal ein konkretes Besipiel wozu du

    reserviere Speicher1
    reserviere Speicher2
    

    brauchst.

    Also es handelt sich dabei um Bilder. Ich bekomme (habe ich oben weggelassen) Farbbilder übergeben die ich dann in Schwarzweiß-Bilder konvertieren muss. Ich benutze OpenCV und muss daher mit cvCreateImage Speicher reservieren.

    Das sieht ungefähr so aus:

    IplImage* imageBW1 = cvCreateImage ( imgSize, IPL_DEPTH_32F, 1 );
    IplImage* imageBW2 = cvCreateImage ( imgSize, IPL_DEPTH_32F, 1 );

    Leider weiß ich nicht was RAll bedeuten soll und das:
    # std::tr1::scoped_ptr
    # boost::scoped_ptr
    # std::auto_ptr
    habe ich noch nie gesehen... 😞

    Der Speicher wird mit cvReleaseImage wieder freigegeben.

    Moritz



  • Moritz06 schrieb:

    Leider weiß ich nicht was RAll bedeuten soll und das:
    # std::tr1::scoped_ptr
    # boost::scoped_ptr
    # std::auto_ptr
    habe ich noch nie gesehen... 😞

    Kennst du Suchmaschinen? Oder vielleich Wikipedia?



  • Don't bite my head off.

    Das Problem ist, dass ich gelesen haben, dass ich den Speicher nicht mit delete freigeben kann.

    The cvCreate* return a pointer wich corresponds to what would happen
    using new. but you cannot use delete or free, you must use cvRelease*
    to clean up.

    http://tech.groups.yahoo.com/group/OpenCV/message/56349

    Es tut mir leid, das hätte ich oben sagen sollen. Es war mir aber auch nicht so bewusst.



  • In RAII Manier macht man sowas entweder etwa so

    class Image
    {
    public
      Image(a, b, c)
       :img_(CreateImage(a,b,c))
      {}
      ~Image()
      {
        try{ReleaseImage(img_);}
        catch(...){}
      }
      // Access to Image...
    private:
     IplImage* img_;
    };
    

    oder mit einer generischen Lösung wie scoped_ptr o.ä. Denen muss man dann nur sagen, dass ReleaseImage statt delete benutzt werden muss.



  • Moritz06 schrieb:

    Das Problem ist, dass ich gelesen haben, dass ich den Speicher nicht mit delete freigeben kann.

    Kein Problem, das ist kein Argument gegen RAII. Schau's dir mal an:

    http://de.wikipedia.org/wiki/RAII

    Du kannst dir einfach eine kleine Klasse bauen, die im Destruktor cvRelease ausführt.



  • Ah ok, viele Dank. Das werde ich ausprobieren.



  • OpenCV hat (spätestens seit V2.1) auch ein C++-Interface, da brauchst du dich dann gar nicht mehr um den Speicher kümmern!

    cv::Mat img1 = cv::imread("bild.jpg"); // oder so ähnlich
    Kann ich nur empfehlen, geht alles viel einfacher damit



  • Tachyon schrieb:

    • std::tr1::scoped_ptr

    Gibts leider nicht, was ich immer noch nicht nachvollziehen kann. Ich wäre schon ein paar Male um scoped_ptr im TR1 froh gewesen.


Anmelden zum Antworten