2013-02-12 7 views
5

Xcode 4.6でiOS用に開発しています。私はサービス用のライブラリを作成しており、スレッドを起動するために使用します。私の方法の一つは、次のようになります。与えられた未来にアクセスした後、boost :: future <>。then()にアクセスできない

void Service::start(boost::shared_ptr<ResultListener> listener) { 

    boost::future<bool> con = boost::make_future(true); 
    listener->onConnected(); // Works 
    boost::future<bool> initDone = con.then([&, listener](boost::future<bool>& connected) { 
     listener->onConnected(); // Works 
     if (!connected.get()) { 
      listener->onError("..."); 
      return false; 
     } 
     listener->onError("..."); // EXC_BAD_ACCESS 
     /* ... */ 
     return true; 
    }); 
} 

デバイス上でこれを実行し、私はマークされたラインでEXC_BAD_ACCESSを取得します。私はonConnectedへの最初の呼び出しが成功し、onErrorを追加してもifの前に呼び出されても、これが非常に驚いています。

C++にはとても慣れていないので、理由が何であるか、どのようにデバッグするのか、この問題が次に起こったかどうかを知る方法について、あらゆる情報について喜んでいます。また、私はどの情報が関連しているのかよく分かりません。私が考えたことは、これまでに私が見つけたものと関連があります。ResultListenerServiceboost::noncopyableです。私はshared_ptruse_countを使って)の参照カウントをチェックし、それは継続の中で増加します。私はブースト1.53を使用しています。この方法は、メソッドが呼び出された場合std::coutに何もなく、プリントしません単純なクラスであること、この

Servuce reco(/* ... */); 
boost::shared_ptr<foo> f(new foo()); 
reco.start(f); 

fooのように呼ばれています。

編集:がさらに周りスヌーピングget()コールを検査するために私を聞かせて、私はfuture.hppに次のコードを発見したが実行されている:

// retrieving the value 
    move_dest_type get() 
    { 
     if(!this->future_) 
     { 
      boost::throw_exception(future_uninitialized()); 
     } 

     future_ptr fut_=this->future_; 
     this->future_.reset(); 
     return fut_->get(); 
    } 

私はこれが問題だと思います。 reset()への呼び出しは、future_shared_ptrのメモリを解放しているようです。私の推測では、これは、継続がOSで使用されていないとして実行されているメモリをマークして、listenerポインタを無効にします。この仮定は正しいですか?どういうわけかこれを避けることができますか、これはブーストのバグですか?

編集2:次のように問題を作成し、最小限の例です:

#define BOOST_THREAD_VERSION 4 
#include <boost/thread.hpp> 

class Test { 

public: 
    void test() { 
     boost::shared_ptr<Test> listener(new Test()); 
     boost::future<bool> con = boost::make_future(true); 
     listener->foo(); // Works 
     boost::future<bool> initDone = con.then([listener](boost::future<bool>& connected) { 
      listener->foo(); // Works 
      if (!connected.get()) { 
       listener->foo(); 
       return false; 
      } 
      listener->foo(); // EXC_BAD_ACCESS 
      return true; 
     }); 
    } 

    void foo() { 
     std::cout << "foo"; 
    } 
}; 

私はconitnuationが実行されている将来の状況を示すために、Xcodeで取って、それはそう2枚のスクリーンショットを追加しましたMankarnas(コメント内)と私(上)は正しいです:継続が保存されているメモリ部分が解放されているため、未定義の動作が発生するようです。

このget()前に状況が呼び出されている: Situation before <code>get</code> is called

これはget()が呼び出された後の状況です: Situation after <code>get</code> was called

アドレスpxポイントその後0x00であるために。

+0

'onError'をチェックしましたか? – inf

+0

どういう意味ですか?それには間違ったコードが含まれていますか?これは 'std :: cout <<" foo ";'で構成され、将来の 'get()'呼び出しの前に 'onError'を呼び出すと動作します。 – Stephan

+0

クラッシュする行の前に 'listener.get()'はnullではありませんか? (私は問題をローカルに再現することはできません;あなたが問題を示す_complete_テストケースを作成できれば、おそらくあなたが記述していない部分について推測する必要はありません)。 – Mankarse

答えて

2

私はバグ1.53 and it was confirmedに対してチケットをオープンしました。 future.thenはまだ安定していないため、プロダクションでは使用できません。そこから一つアドバイスが

#define BOOST_THREAD_DONT_PROVIDE_FUTURE_INVALID_AFTER_GET 

を使用していた。しかし、それは明らかに、この機能はまだ安定していない(とドキュメントが情報のこのビットを欠いていること)と述べました。

私は今、別のスレッドを使用して、将来を待って適切なアクションを実行するように切り替えました。