我正在 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
(using 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
. 我的猜测是,这将继续运行的内存标记为未用于操作系统,从而使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(在评论中)和我(上图)似乎是正确的:似乎是存储 continuation 的内存部分被释放,因此发生未定义的行为。
这是之前get()
称为的情况:
这是get()
调用后的情况:
地址px
指向的是0x00
之后。