【问题标题】:Passing values to atexit将值传递给 atexit
【发布时间】:2011-11-08 15:39:27
【问题描述】:

我想在需要时推送一系列清理功能。我正在使用 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

提前致谢!

【问题讨论】:

    标签: c++ boost-bind atexit


    【解决方案1】:

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

    最糟糕的解决方案是将该参数存储在全局变量中,并在 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

    【讨论】:

    • 注意:存储范围时,请确保它所基于的集合在您需要使用该范围时仍然存在。
    【解决方案2】:

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

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

    【讨论】:

    • 这似乎非常有用。为什么是遗产? :-)
    • @Misha 因为你不能传递参数,而且你在 C++ 中不需要它;只需定义一个静态变量,其析构函数可以为所欲为。
    【解决方案3】:

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

    你可以试试这个:

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

    【讨论】:

    • 我想有一些解决方法,例如有一个充满与字符串对应的值的向量,但我希望在一行中完成它而不会使我的代码进一步复杂化:-)
    猜你喜欢
    • 1970-01-01
    • 2015-12-09
    • 2014-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多