Resource Aquisition Is Initialization
 
StartSeite | Neues | TestSeite | ForumSeite | Teilnehmer | Kategorien | Index | Hilfe | Einstellungen | Ändern

Das folgende ist einem Beitrag von RalfEbert auf der freedict-mailing-list entnommen. Es geht um das Problem der sicheren Resourcenfreigabe im Bezug auf die Verwendung von Exceptions.

[Hallo Liste, ich habe mich inzwischen in meinem schlauen Buch (2. Auflage von BjarneStroustrup) schlau gemacht. Hier das Ergebnis unter besonderer Berücksichtigung der Bedenken von Helmut (und auch meiner eigenen): --rae]


nicht freigegebene Resorcen
Der Ansatz 'resource aquisition is initialization' erschlägt das Problem, da hierbei Resourcen als Klassen angefordert werden. Z.B. kann die Resource 'FILE' auch durch eine Klasse gekapselt werden:

  class FilePtr {
      FILE *file;
    public:
      FilePtr(const char *nameOfFile, const char *kindOfAccess) {
        file = fopen(nameOfFile, kindOfAccess);
      }
      FilePtr(FILE *filePtr) {
        file = filePtr;
      }
      ~FilePtr() {
        fclose(file);
      }

    operator FILE*() {
      return(file);
    }
  };

Dann kann in einer Funktion 'useFile()' die Resource FILE auch nach einer Exception automatisch wieder freigegeben werden, da sich die Klasse auf dem lokalen Stack befindet und daher am Ende der Funktion oder bei dem Passieren der Funktion durch eine Exception automatisch wieder freigegeben wird.

  void useFile(const char *nameOfFile) {
    FilePtr f(nameOfFile, "r");

    // Code, der 'f' verwendet
  }

Memory-Leaks

Das gleiche kann man mit Speicher machen, der dynamisch angefordert wird, solange er nur in der anfordernden Funktion selbst benutzt wird. Soll der angeforderte Speicherblock z.B. als Ergebnis an die rufende Funktion uebergeben werden, so muss die Funktion, die den Speicher allokiert, alle Exceptions auffangen und zumindest den Speicher wieder frei geben. Kann die Funktion die Exception(s) nicht abschliessend behandeln, so kann sie die Exception ihrerseits danach wieder weiterwerfen.

Zwei-Phasen-Konzept

Bei Zustandsveränderungen von bestehenden Objekten muss aber trotzdem ein 2-Phasen-Konzept eingehalten werden, wenn die Zustandsveränderung (z.B. Zuweisung) Exception-sicher sein soll: Zuerst müssen alle "neu benötigten" Resourcen an initialisierte Objekte gebunden werden, dann erst darf die eigentliche Zustandsänderung beginnen.

Wer das 2-Phasen-Sperrkonzept zur Sequentialisierung von Transaktionen kennt, kann eine Zustandsänderung als Transaktion auffassen und muss nichts neues dazulernen. Erst wenn alle "Sperren" erfolgreich gesetzt sind, darf eine davon auch genutzt werden.

Undifferenzierte Rueckgabewerte bei Exceptions

Man kann Ausnahmen auch einen Wert mitgeben:

  class Vector {
      // diverse interne Variablen
    public:
      class Range {
        public:
          int index;
          Range(int i) : index(i) {}
      };    
      // ...
      int &operator[](int i);
      // ...
  };

  int &Vector::operator[](int i) {
    if (i < 0 || sizeOfList <= i)
      throw Range(i);
    return(member[i]);
  }


Meines Wissens kann man dieses Verfahren nicht 1:1 auf Java umsetzen, da dort Objekte nie am Stack angelegt werden (dort liegt immer nur eine Referenz) und weil die Freigabe von Objekten an die GarbageCollection gebunden, also dem Zufall überlassen ist. Der Weg, den man in Java gehen muss, ist der über explizite "finalize"-Funktionsteile in jeder resourcenverwendenden Funktion. Ist das korrekt, oder habe ich da etwas falsch verstanden? -- HelmutLeitner

Ist korrekt, hast Du richtig verstanden. ;-) -- IljaPreuß


KategorieCpp KategorieOop
StartSeite | Neues | TestSeite | ForumSeite | Teilnehmer | Kategorien | Index | Hilfe | Einstellungen | Ändern
Text dieser Seite ändern (zuletzt geändert: 17. Juli 2002 11:32 (diff))
Suchbegriff: gesucht wird
im Titel
im Text