Pasando valores a atexit

Quiero impulsar una serie de funciones de limpieza a medida que sean necesarias. Estaba usando atexit para hacer esto para una función de limpieza sin ningún parámetro, pero no estoy seguro de cómo expandir este enfoque a más de una función de limpieza. No estoy muy familiarizado con boost :: bind, pero asumí que sería una buena idea ya que así es como enlacé mis funciones a los subprocesos ...

En c ++ estoy tratando de hacer que funcione lo siguiente:

Definición de función

static void closeAnimation(string prefix="");// static member of fileWriter

Código:

atexit(boost::bind(fileWriter::closeAnimation, "0")); // I want to first prefix to be "0"

El error:

cannot convert ‘boost::_bi::bind_t<void, void (*)(std::basic_string<char>), boost::_bi::list1<boost::_bi::value<const char*> > >’ to ‘void (*)()’ for argument

Gracias de antemano!

preguntado el 08 de noviembre de 11 a las 15:11

3 Respuestas

No existe una "solución de 1 línea sin complicar su código".

La peor solución es almacenar ese parámetro en una variable global y recuperarlo en el controlador atexit

Dado que está utilizando C ++, el destructor de una variable estática también podría servir como un atexit manipulador. Luego puede pasar el parámetro en el constructor de esa variable estática para la parametrización, por ejemplo

struct AtExitAnimationCloser
{
    const char* _which_param;

    AtExitAnimationCloser(const char* which_param) : _which_param(which_param) {}
    ~AtExitAnimationCloser() { FileWriter::closeAnimation(_which_param); }
};

void f()
{
    printf("entering f\n");

    static AtExitAnimationCloser s0 ("0"); // registers closeAnimation("0") at exit
    static AtExitAnimationCloser s1 ("1"); // registers closeAnimation("0") at exit

    printf("leaving f\n");
}

Demostración: http://www.ideone.com/bfYnY

Tenga en cuenta que las variables estáticas están vinculadas a su nombre, por lo que no puede decir

for (it = vecs.begin(); it != vecs.end(); ++ it)
{
   static AtExitAnimationCloser s (*it);
}

llamar atexit para todo el contenido. Pero podrías hacer que la variable estática en sí tome un rango completo

static AnotherAtExitAnimationCloser s (vecs.begin(), vecs.end())

Finalmente, con C ++ idiomático no creo que necesites usar estos trucos ... Podrías almacenar un vector de tipos T, que en la destrucción ~ T llama fileWriter::closeAnimation.

respondido 08 nov., 11:20

Nota: al almacenar un rango, asegúrese de que la colección en la que se basa sobreviva mientras necesite usar el rango. - Matthieu M.

atexit es una función heredada de C y no muy adaptada a C ++. Puede registrar más de una función con atexit, pero todos deben ser void (*)()En boost::function y sin argumentos.

En C ++, la mayoría, si no todos atexitLa funcionalidad de ha sido subsumida por los destructores de objetos estáticos. En tu caso, escribiría algo como:

#include <vector>

class CallInDestructor
{
    class Registry
    {
        std::vector<CallInDestructor*> myInstances;
    public:
        register_caller(CallInDestructor* caller)
        {
            myInstances.push_back(caller);
        }
        ~Registry()
        {
            while ( !myInstances.empty() ) {
                delete myInstances.back();
                myInstances.pop_back();
            }
        }
    };
    static Registry& registry()
    {
        static Registry theOneAndOnly;
        return theOneAndOnly;
    }

protected:
    CallInDestructor() { registry().register_caller( this ); }

public:
    virtual ~CallInDestructor() {}
};

template<typename Fnc> void callAtExit( Fnc fnc );

template<typename Fnc>
class ConcreteCallInDestructor : public CallInDestructor
{
    Fnc myFnc;
    ConcreteCallInDestructor( Fnc fnc = Fnc() ) : myFnc( fnc ) {}
    virtual ~ConcreteCallInDestructor() { myFnc(); }

    friend void callAtExit<Fnc>( Fnc fnc );
};

template<typename Fnc>
void
callAtExit( Fnc fnc )
{
    new ConcreteCallInDestructor<Fnc>( fnc );
}

Utilizan callAtExit como lo harías atexit, pero debería funcionar para cualquier cosa que se pueda llamar sin argumentos (incluida una boost::function). O puede escribir sus propias clases derivadas de CallInDestructor, siempre que tome medidas para asegurarse de que todas las instancias se asignen dinámicamente (ya que el constructor registra el objeto para que se elimine); estas clases pueden contener cualquier dato adicional que desee.

Respondido el 07 de enero de 13 a las 10:01

Parece increíblemente útil. ¿Por qué es un legado? :-) - Mikhail

@Misha Porque no puedes pasarle argumentos y porque no lo necesitas en C ++; simplemente defina una variable estática cuyo destructor haga lo que quiera. - James Kanze

El problema es que bind devuelve un objeto de función y atexit toma un puntero a una función que devuelve void y no toma ningún parámetro.

Puedes intentar esto:

void fun() {
    fileWriter::closeAnimation("0");
}

atexit(fun);

respondido 08 nov., 11:19

Supongo que hay algunas soluciones, como tener un vector lleno de los valores que corresponden a las cadenas, pero esperaba hacerlo en una línea sin complicar más mi código :-) - Mikhail

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.