4

必要に応じて、一連のクリーンアップ機能をプッシュしたいと考えています。パラメータなしで1つのクリーンアップ関数に対してこれを行うために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 関数であり、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 に答える
3

「コードを複雑にせずに 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

于 2011-11-08T15:56:08.703 に答える
-1

問題は、bindが関数オブジェクトを返し、atexitがvoidを返し、パラメーターを受け取らない関数へのポインターを受け取ることです。

あなたはこれを試すことができます:

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

atexit(fun);
于 2011-11-08T15:45:27.197 に答える