Domanda

Ho letto l'articolo sull'ambito guardie (Generico:Cambiare il Modo di Scrivere il Codice di Eccezioni — per Sempre) in DDJ e capisco il loro uso comune.

Tuttavia, l'uso comune è quello di creare un'istanza di un particolare stack di guardia sullo stack per una particolare operazione, ad esempio:

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

ma cosa succede se voglio pianificare le operazioni di pulitura in fase di runtime, ad esempioquando ho un ciclo:

{
   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
   }
}

Ovviamente, l'esempio di cui sopra non funziona, dato che topSecret sarebbe chiuso con la per ambito di applicazione.Vorrei un ambito guardia motivo per cui posso facilmente in coda operazioni di pulitura che decido di essere necessari in fase di runtime.C'è qualcosa di simile a questo?

Io non riesco a spingere ambito guardia di oggetti in una coda standard, causa l'oggetto originale (quello che io sto spingendo) potrebbe essere respinto nel processo.Come circa spingendo allocazione heap stack guardie e l'utilizzo di una coda che elimina i suoi membri dtor?Qualcuno ha un più approccio intelligente?

È stato utile?

Soluzione

Sembra non apprezzare RAII per quello che è.Questi ambito guardie sono bella occasione per i locali ("ambito di applicazione") le cose, ma si dovrebbe cercare di evitare di loro a favore di ciò che RAII è realmente dovrebbe fare:incapsulamento di una risorsa in un oggetto.Il tipo di FILE* che in realtà è solo che non bene.

Ecco un'alternativa:

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);
    }
}

O:

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);
    }
}

O in "C++0x" (i prossimi standard del C++):

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

Edit:Quanto mi piace caratteri mobili in C++0x tanto e si mostrò interesse:Ecco come si potrebbe utilizzare unique_ptr in combinazione con il FILE* senza ref-conteggio overhead:

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() );
}

(non testato)

Assicurarsi di check out Dave blog di efficienti mobile i tipi di valore

Altri suggerimenti

Eh, scopre la guardia portata DDJ è "mobile", non nel senso C ++ 0x, ma nello stesso senso che un auto_ptr è mobile: durante la ctor copia, la nuova guardia "respinge" vecchia guardia (come la copia ctor di auto_ptr chiama il vecchio uno auto_ptr :: rilascio ).

Così posso semplicemente tenere un queue<ScopeGuard> e funzionerà:

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));
   // ...
}

A proposito, grazie per la risposta di cui sopra. Era informativo ed educativo per me in modi diversi.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top