Frage

habe ich den Artikel über Umfang Wachen lesen ( Allgemein: Ändern Sie den Weg Sie schreiben Exception-Sicher-Code - Forever ) in DDJ und ich verstehe ihre gemeinsame Verwendung

.

Allerdings ist die gemeinsame Verwendung ist, eine bestimmte Stack-Guard auf dem Stapel für einen bestimmten Vorgang zu instanziiert, z.

{
    FILE* topSecret = fopen("cia.txt");
    ON_BLOCK_EXIT(std::fclose, topSecret);
    ... use topSecret ...
} // topSecret automagically closed

aber was, wenn ich will Zeitplan Bereinigungsvorgänge im laufenden Betrieb, zum Beispiel wenn ich eine Schleife:

{
   vector<FILE*> topSecretFiles;
   for (int i=0; i<numberOfFiles; ++i)
   {
      char filename[256];
      sprintf(filename, "cia%d.txt", i);
      FILE* topSecret = fopen(filename);
      topSecretFiles.push_back(topSecret);
      ON_BLOCK_EXIT(std::fclose, topSecret); // no good
   }
}

Offensichtlich würde das obige Beispiel nicht arbeiten, da topSecret würde zusammen mit dem für Umfang geschlossen werden. Ich würde ein Rahmen Schutzmuster mag, wo ich kann genauso leicht Bereinigungsvorgänge anstehen, die ich benötigt werden, bestimmen zu zur Laufzeit . Gibt es so etwas wie diese zur Verfügung?

Ich kann nicht Anwendungsbereich Schutzobjekte in eine Standard-Warteschlange schieben, weil das ursprüngliche Objekt (die ich drängen) würde in den Prozess zurückzuweisen. Wie wäre es drängen Heap zugewiesenen Stapel Wachen und unter Verwendung einer Warteschlange, die ihre Mitglieder auf dtor löscht? Hat jemand einen cleveren Ansatz hat?

War es hilfreich?

Lösung

Es scheint, dass Sie nicht zu schätzen wissen RAII für das, was es ist. Diese Rahmen Wachen sind schön gelegentlich für die lokale ( „scope“) Dinge, aber Sie sollten versuchen, sie für zu vermeiden, was RAII ist wirklich tun soll: eine Ressource in einem Objekt eingekapselt wird. Der Typ FILE * ist wirklich einfach nicht gut darin.

Hier ist eine Alternative:

void foo() {
    typedef std::tr1::shared_ptr<FILE> file_sptr;
    vector<file_sptr> bar;
    for (...) {
        file_sptr fsp ( std::fopen(...), std::fclose );
        bar.push_back(fsp);
    }
}

Oder:

void foo() {
    typedef std::tr1::shared_ptr<std::fstream> stream_sptr;
    vector<stream_sptr> bar;
    for (...) {
        file_sptr fsp ( new std::fstream(...) );
        bar.push_back(fsp);
    }
}

oder in "C ++ 0x" (kommenden C ++ Standard):

void foo() {
    vector<std::fstream> bar;
    for (...) {
        // streams will become "movable"
        bar.push_back( std::fstream(...) );
    }
}

Edit: Da ich wie beweglichen Lettern in C ++ 0x so viel, und Sie zeigte Interesse daran: Hier ist, wie Sie in Kombination mit FILE verwenden unique_ptr könnte * ohne ref Zählung Kopf :

struct file_closer {
    void operator()(FILE* f) const { if (f) std::fclose(f); }
};

typedef std::unique_ptr<FILE,file_closer> file_handle;

file_handle source() {
    file_handle fh ( std::fopen(...) );
    return fh;
}

int sink(file_handle fh) {
    return std::fgetc( fh.get() );
}

int main() {
    return sink( source() );
}

(ungetestet)

Seien Sie sicher Daves Blog auf effiziente beweglichen Werttypen

Andere Tipps

Huh, abwechselnd aus der DDJ Umfang Wache ist „beweglich“, nicht in dem C ++ 0x Sinne, aber im gleichen Sinne, dass ein auto_ptr beweglich ist: während des Kopierens Ctor, die neue Garde „entlässt“ die alte Garde (wie auto_ptr Kopie ctor ruft die alte jemandes auto_ptr :: Release ).

So kann ich einfach ein queue<ScopeGuard> halten und es wird funktionieren:

queue<ScopeGuard> scopeGuards;

// ...

for (...)
{
   // the temporary scopeguard is being neutralized when copied into the queue,
   // so it won't cause a double call of cleanupFunc
   scopeGuards.push_back(MakeScopeGuard(cleanupFunc, arg1));
   // ...
}

Übrigens, danke für die Antwort oben. Es war informativ und lehrreich für mich auf unterschiedliche Weise.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top