我正在为XCode 4.6中的iOS开发。我正在为服务编写一个库,并使用boost来启动线程。我的一种方法看起来像这样:
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
)并且在连续中增加了。我正在使用boost 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
的记忆。我的猜测是,这标志着延迟仍然在运行的内存,因为没有用于操作系统,因此使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中添加了两个截图,以显示将来运行conitnuation的情况,似乎Mankarnas(在评论中)和我(上面)是正确的:它似乎是内存部分,其中存储的延续被释放,因此发生了未定义的行为。
这是调用get()
之前的情况:
调用get()
后的情况如下:
之后地址px
指向0x00
。
答案 0 :(得分:2)
我打开了一张针对提升1.53 and it was confirmed的罚单作为错误。似乎future.then
尚未稳定,因此尚未准备好用于生产。一个建议是使用
#define BOOST_THREAD_DONT_PROVIDE_FUTURE_INVALID_AFTER_GET
但有人明确表示此功能尚不稳定(并且文档缺少这些信息)。
我现在已经切换到使用一个单独的线程,我将等待未来并执行适当的操作。