XCode4.6でiOS用に開発しています。私はサービス用のライブラリを作成していて、boostを使用してスレッドを開始しています。私の方法の1つは次のようになります。
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 ++にまったく慣れていないので、理由、デバッグ方法、次回この問題が発生した場合の認識方法に関するすべての情報に満足しています。また、どの情報が関連しているかはよくわかりません。私が考えたものは、これまでに見つけたものと関連している可能性があります。次の可能性がResultListener
ありService
ますboost::noncopyable
。shared_ptr
(を使用して)の参照カウントを確認したuse_count
ところ、継続内で増加しています。私はブースト1.53を使用しています。メソッドはこのように呼び出されます
Servuce reco(/* ... */);
boost::shared_ptr<foo> f(new foo());
reco.start(f);
foo
std::cout
メソッドが呼び出された場合に出力する以外に何もしない単純なクラスです。
編集:さらにスヌーピングして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";
}
};
XCodeで撮った2つのスクリーンショットを追加して、継続が実行されている将来の状況を示しています。Mankarnas(コメント内)と私(上記)は正しいようです。継続が保存されているメモリ部分のようです。が解放されるため、未定義の動作が発生します。
これは、以前get()
は次のように呼ばれる
状況です。
get()
これは、呼び出され
た後の状況です。
px
が指すアドレスは0x00
後でです。