2011-11-08 6 views
3

必要に応じて一連のクリーンアップ機能をプッシュしたいと思います。私はatexitを使用して、パラメータなしで1つのクリーンアップ関数を実行していましたが、このアプローチを複数のクリーンアップ関数に拡張する方法がわかりません。私はboost :: bindに詳しくはわかりませんが、スレッドに関数をバインドする方法としては良い考えであると仮定しています...atexitに値を渡す

私は以下のコードを実行しようとしています:

関数定義

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 

ありがとうございます!

答えて

2

には、「あなたのコードを複雑にすることなく1つのラインソリューション」はありません。

最悪の解決策は、あなたがC++を使っているので、静的変数のデストラクタもatexitハンドラとして役立つ可能性がグローバル変数にそのパラメータを格納し、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

(注)すべてのコンテンツのためのatexitを呼び出すために

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

を言うことができないので、静的変数は、その名前にバインドされていること。しかし、あなたは慣用的なC++私はあなたがこれらのトリックを使用する必要はないと思うと...あなたはどの破壊で〜、タイプTのベクトルを格納することができ、静的変数自体は、全体の範囲に最後に

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

を取る作ることができますTはfileWriter::closeAnimationを呼び出します。

+0

注:範囲を保存するときは、範囲を使用する必要がある限り、そのコレクションが存続することを確認してください。 –

0

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

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

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

atexit(fun); 
+0

コードに文字列に対応する値がいっぱいのような回避策があると思いますが、私のコードをさらに複雑にすることなく1行でやりたいと考えていました。 – Mikhail

3

atexitは、従来のC関数であり、C++にあまり適応していません。 は複数の機能をatexitで登録できますが、すべてが void (*)()で、引数がない場合はboost::functionである必要があります。

C++では、atexitの機能のすべてではないにしても、大部分は静的オブジェクトのデストラクタによって包含されています。 あなたがatexitだろうが、それは(boost::function含む)引数なしで呼び出すことができるもの のために働く必要がありますよう

#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:あなたのケースでは、私のような何か を記述します。 から派生した独自のクラスを と書くと、すべてのインスタンスが動的に に割り当てられるようにすることができます(コンストラクタがオブジェクトを登録するので、 が削除されます)。これらのクラスには、必要な追加データを含めることができます。

+0

それは信じられないほど役に立つと思われます。なぜそれは遺産ですか? :-) – Mikhail

+1

@Mishaあなたは引数を渡すことができないし、C++ではそれを必要としないので、デストラクタが必要なものを実行する静的変数を定義するだけです。 –