4

我想根据需要推送一系列清理功能。我正在使用 atexit 为一个没有任何参数的清理函数执行此操作,但我不确定如何将这种方法扩展到一个以上的清理函数。我对 boost::bind 不是很熟悉,但认为这是一个好主意,因为这就是我将函数绑定到线程的方式......

在 c++ 中,我试图让以下工作:

功能定义

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

代码:

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

错误:

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

提前致谢!

4

3 回答 3

3

没有“不使您的代码复杂化的单行解决方案”。

最糟糕的解决方案是将该参数存储在全局变量中,并在 atexit 处理程序中检索它

由于您使用的是 C++,因此静态变量的析构函数也可以用作atexit处理程序。然后您可以在该静态变量的构造函数中传递参数以进行参数化,例如

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

演示:http ://www.ideone.com/bfYnY

请注意,静态变量绑定到它们的名称,所以你不能说

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

为所有内容调用 atexit。但是你可以让静态变量本身占据整个范围

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

最后,使用惯用的 C++,我认为您不需要使用这些技巧……您可以存储类型为 T 的向量,在破坏时 ~T 调用fileWriter::closeAnimation.

于 2011-11-08T15:56:08.703 回答
3

atexit是一个遗留的 C 函数,不太适应 C++。您可以使用 注册多个函数atexit,但所有函数都必须是 void (*)()、没有boost::function和没有参数。

在 C++ 中,大多数(如果不是全部atexit)的功能都被静态对象的析构函数所包含。在你的情况下,我会写这样的东西:

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

callAtExit像你一样使用atexit,但它应该适用于任何可以不带参数调用的东西(包括 a boost::function)。或者您可以编写自己的派生自 的类CallInDestructor,只要您采取措施确保所有实例都是动态分配的(因为构造函数注册了该对象以便将其删除);这些类可以包含您想要的任何其他数据。

于 2011-11-08T16:29:37.623 回答
-1

问题是 bind 返回一个函数对象,而 atexit 需要一个指向返回 void 且不带参数的函数的指针。

你可以试试这个:

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

atexit(fun);
于 2011-11-08T15:45:27.197 回答