2016-10-07 5 views
4

私はシンプルで柔軟なイベントシステムをプログラムしようとしています(実際には、実際のイベントハンドラを持っている既存のライブラリがあると思います)。そして私はちょっとした障害に遭遇しました。呼び出し前にstd :: functionの有効性をチェックしますか?

代理人であるstd::function(おそらくラムダを通して、おそらくはstd :: bindを介して)が有効な関数/メンバー関数のオブジェクトがそれを呼び出す前にまだ存在するかどうかを確認できますか?私は単にstd::function's bool演算子を使ってみましたが、何の成功もありませんでした。

理想的にはA.デリゲート関数内以外の場所でチェックを行い、チェックされているstd ::関数がデリゲートでない場合でもB.が有効なコードを持っていることが理想的です。

アイデア?

編集:あなたはこの場合

#include <iostream> #include <string> #include <functional> #include <memory> class Obj { public: std::string foo; Obj(std::string foo) : foo(foo) {} void delegatedFn() { std::cout << foo << std::endl; } }; int main() { auto obj = std::make_shared<Obj>("bar"); std::weak_ptr<Obj> ptr = obj; std::function<void()> callback = [ptr](){ auto sh = ptr.lock(); if(sh) { std::cout << "valid" << std::endl; sh->delegatedFn(); } else { std::cout << "invalid" << std::endl; } }; callback(); obj = nullptr; callback(); return 0; } 

ここで私はあなたの代わりに裸なもののスマートポインタを( std::shared_ptr/ std::weak_ptr)を使用することができます

#include <iostream> 
#include <string> 
#include <functional> 

class Obj { 
public: 
    std::string foo; 
    Obj(std::string foo) : foo(foo) {} 
    std::function<void()> getDelegate() { 
     auto callback = [this]() {this->delegatedFn();}; 
     return callback; 
    } 
    void delegatedFn() { 
     std::cout << foo << std::endl; 
    } 
}; 

int main() { 
    Obj* obj = new Obj("bar"); 
    std::function<void()> callback = obj->getDelegate(); 
    callback(); 
    delete obj; 

    //perform some type of check here whether function is valid, without needing to know whether the function is a delegate or not 
    if(callback) { 
     std::cout << "Callback is valid" << std::endl; //callback is still considered valid after obj is deleted 
     callback(); //no exception thrown, prints a random series of characters 
    } 
    else { 
     std::cout << "Callback is invalid" << std::endl; 
    } 

    return 0; 
} 
+0

お試しいただいた内容をお見せできますか?好ましくは、[最小限の完全かつ検証可能な例](http://stackoverflow.com/help/mcve)。また、あなたが得るどんな誤りも含みます。 –

+5

ランダムなポインタが有効なオブジェクトを指しているかどうかをチェックすることはできません。ユースケースは同じものになります。 –

+0

あなたのサンプルコードを見てから、これは、 'Obj'クラスがメンバ変数' foo'へのポインタを返した関数を持っていて、 'Obj'クラスの後に' 「obj」が削除されました。可能な唯一のことは、あなた自身でそれを追跡することです。ライブラリーやコンパイラーがここで助けてくれる "魔法"はありません。 –

答えて

4

を実行したテスト用のソースです妥当性std::functionであることを直接確認していません(たとえ割り当てても有効です)。その場合でも何かはぶら下がりポインタを捕捉します)。
代わりに、参照されたオブジェクトが関数自体からまだ生存していることを確認します。

2

は、私が使用して放送/リスナーパターンは次のようになります。

template<class...Args> 
struct broadcaster { 
    std::vector< std::weak_ptr< std::function<void(Args...)> > > callbacks; 

    void operator()(Args...args) const { 
    std::remove_erase_if(begin(callbacks), end(callbacks), [](auto&& ptr){return !ptr;}); 
    auto tmp = callbacks; 
    for (auto pf : tmp) { 
     if (pf && *pf) (*pf)(args...); 
    } 
    } 
    std::shared_ptr<void> listen(std::shared_ptr<std::function<void(Args...)>> f) { 
    callbacks.push_back(f); 
    return f; 
    } 

    std::shared_ptr<void> listen(std::function<void(Args...)> f) { 
    auto ptr = std::make_shared<std::function<void(Args...)>>(std::move(f)); 
    return listen(ptr); 
    } 
}; 

リスナーのメッセージ.listenbroadcasterとのコールバックに。彼らはshared_ptr<void>トークンを返します。

限りそのトークンが存在するとして、放送局は、渡された関数オブジェクトでメッセージを送信します。

Objstd::vector<std::shared_ptr<void>> tokensまたは単一std::shared_ptr<void>を格納しますどちらか。破棄されたとき、そのリスナーは自動的に登録抹消されます。

また、Objshared_from_thisから継承できます。それはObjインスタンス自体の寿命を共有

std::function<void()> delegate; 
std::shared_ptr<std::function<void()>> getDelegatedFn() { 
    if (!delegate) delegate = [this]{ this->delegateFn(); } 
    return { 
    &delegate, 
    shared_from_this() 
    }; 
} 

shared_ptrのエイリアシングコンストラクタを使用)を実装します。これをlistenに渡して完了します。

関連する問題