Question

I want to push a series of clean up functions as they are needed. I was using atexit to do this for one cleanup function without any parameters, but I am not sure how to expand this approach to more then one clean up function. I am not very familiar with boost::bind, but assumed it would be a good idea as that is how I binded my functions to threads...

In c++ I am trying to get the following to work:

Function Definition

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

Code:

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

The 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

Thanks in advance!

Was it helpful?

Solution

There is no "1 line solution without complicating your code".

The worst solution is to store that parameter in a global variable, and retrieve it in the atexit handler

Since you're using C++, the destructor of a static variable could also serve as an atexit handler. Then you can pass parameter at the constructor of that static variable for parametrization, e.g.

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

Demonstration: http://www.ideone.com/bfYnY

Note that static variables are bound to their name, so you cannot say

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

to call atexit for all the content. But you could make the static variable itself take whole range

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

Finally, with idiomatic C++ I don't think you need to use these tricks... You could store a vector of types T, which on destruction ~T calls fileWriter::closeAnimation.

OTHER TIPS

atexit is a legacy C function, and not very adapted to C++. You can register more than one function with atexit, but all of them must be void (*)(), no boost::function and no arguments.

In C++, most, if not all of atexit's functionality has been subsumed by the destructors of static objects. In your case, I'd write something like:

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

Use callAtExit as you would atexit, but it should work for anything which can be called with no arguments (including a boost::function). Or you can write your own classes deriving from CallInDestructor, as long as you take steps to ensure that all instances are dynamically allocated (since the constructor registers the object so that it will be deleted); these classes can contain any additional data you want.

The problem is that bind returns a function object, and atexit takes a pointer to a function that returns void and takes no parameter.

You can try this:

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

atexit(fun);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top