Pregunta

He leído el artículo sobre guardias de alcance ( Genérico: Cambiar la forma de escribir Excepción-Safe Código -. para siempre) en el DDJ y entiendo su uso común

Sin embargo, el uso común es para instanciar un guardia de pila particular, en la pila para una operación particular, por ejemplo:.

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

pero lo que si quiero programar las operaciones de limpieza en tiempo de ejecución, por ejemplo, cuando tengo un bucle:

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

Obviamente, el ejemplo anterior no funcionaría, ya que topSecret estaría cerrado junto con el de alcance. Me gustaría un patrón de vigilancia ámbito en el que sólo puede cola, ya que fácilmente las operaciones de limpieza, que lo determinen que son necesarios en tiempo de ejecución . ¿Hay algo como esto disponible?

No puedo empujar objetos guardia alcance en una cola estándar, hacer que el objeto original (el que yo estoy empujando) sería despedido en el proceso. ¿Qué hay de empujar los guardias de la pila de lixiviación en el uso asignado y una cola que borra sus miembros en dtor? ¿Alguien tiene un enfoque más inteligente?

¿Fue útil?

Solución

Parece que no se dan cuenta RAII para lo que es. Estos protectores de alcance son agradables en ocasiones cosas locales ( "alcance"), pero se debe tratar de evitarlos en favor de lo que RAII se supone realmente que hacer: la encapsulación de un recurso en un objeto. El tipo de archivo * es realmente no es bueno en eso.

Esto es una 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 en "C ++ 0x" (próxima C ++ estándar):

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

Edit: Ya que me gusta tipos móviles en C ++ 0x tanto y que mostraron interés en él: He aquí cómo usted podría utilizar unique_ptr en combinación con el archivo * sin ningún ref-contando sobrecarga :

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

(no probado)

Asegúrese de revisar el blog de Dave en los tipos de valor móviles eficientes

Otros consejos

Huh, resulta que el guardia de alcance DDJ es "móvil", no en el sentido de C ++ 0x, pero en el mismo sentido que un auto_ptr es móvil: durante el ctor copia, la nueva guardia "descarta" la vieja guardia (como copia de Héctor auto_ptr llama de la antigua auto_ptr :: liberación ).

Así que simplemente guardar un queue<ScopeGuard> y va a trabajar:

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

Por cierto, gracias por la respuesta anterior. Fue informativo y educativo para mí de diferentes maneras.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top