【发布时间】:2015-02-06 04:20:45
【问题描述】:
所以我有这个函数来添加侦听器,它会转换类的共享指针,以便稍后在收到通知时调用它。
void registerListener(std::shared_ptr<T> listener)
{
if (!listener) {
qCWarning(OBSERVER_LOGGER) << "Attempted to register a null observer.";
return;
}
// TODO make a foreach function that removes dead listeners to get rid of this code dupe
for (auto iter=listeners.begin(); iter != listeners.end(); ) {
if (auto shared = iter->lock()) {
if (listener == shared) {
return;
}
iter++;
} else {
iter = listeners.erase(iter);
}
}
auto weak = std::weak_ptr<T>(listener);
listeners.push_back(weak);
}
void notify(std::function<void(std::shared_ptr<T>)> onNotify)
{
// TODO make a foreach function that removes dead listeners to get rid of this code dupe
for (auto iter=listeners.begin(); iter != listeners.end(); ) {
if (auto shared = iter->lock()) {
onNotify(shared);
iter++;
} else {
iter = listeners.erase(iter);
}
}
}
private:
std::vector<std::weak_ptr<T>> listeners;
由于某种原因,“iter->lock()”段错误。我会说这是一个 Qt 应用程序,但我故意没有创建任何线程(据我所知),所以我只是超级困惑我做错了什么以使这些weak_ptrs 中断。所以如果我在 gdb 中运行它,它工作得很好。但是如果我设置,“设置禁用随机化关闭”然后我得到错误。所以我觉得这是一个奇怪的问题,其中有未初始化的变量。如果有帮助,这是我在 gdb 中崩溃时的堆栈。
#0 0x00007f856bd8beec in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_get_use_count() const ()
#1 0x00007f856bd844a8 in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_add_ref_lock_nothrow() ()
#2 0x00007f856bd9cd7d in std::__shared_count<(__gnu_cxx::_Lock_policy)2>::__shared_count(std::__weak_count<(__gnu_cxx::_Lock_policy)2> const&, std::nothrow_t) ()
#3 0x00007f856bda9948 in std::__shared_ptr<IEntityListener<Assignment>, (__gnu_cxx::_Lock_policy)2>::__shared_ptr(std::__weak_ptr<IEntityListener<Assignment>, (__gnu_cxx::_Lock_policy)2> const&, std::nothrow_t) ()
#4 0x00007f856bda8a62 in std::shared_ptr<IEntityListener<Assignment> >::shared_ptr(std::weak_ptr<IEntityListener<Assignment> > const&, std::nothrow_t) ()
#5 0x00007f856bda701a in std::weak_ptr<IEntityListener<Assignment> >::lock() const ()
#6 0x00007f856bda5624 in Observer<IEntityListener<Assignment> >::notify(std::function<void (std::shared_ptr<IEntityListener<Assignment> >)>) ()
#7 0x00007f856bda3a1a in EntityObserver<Assignment>::notifyCreated(std::shared_ptr<Assignment>) ()
编辑:Michael Burr 发布了在添加新听众的同时注册听众的可能性,这完全有可能发生。这将导致迭代器无效,并且当我在不是weak_ptr 的一段内存上调用weak_ptr.lock() 时,BOOM。我认为这里有一个寓意,我只需要找到它。
【问题讨论】:
-
你能给我们一个完整的带有 main() 的最小工作程序吗?
-
您可以将
auto weak = std::weak_ptr<T>(listener);简化为std::weak_ptr<T> weak(listener);。此外,您有一个名为notify()的函数,它接受一个同名的参数 - 这也是一个函数! -
我可以稍后再尝试。实际上我还没有更简单的程序崩溃。没有意义的事情是,在过去的 6 个月里,这很有效,然后我添加了一个新的监听器,然后 BOOM 突然一切都爆炸了。但我什至甚至区分了新的听众和它完全一样!
-
@JohnZwinck 我完全承认我以前从未注意过这个名字。让我解决这个问题。
-
标准现在强制您首先获取 shared_ptr,然后才能使用weak_ptr 的内容。过期版本的 boost 可能更糟,因为它可能会引入竞争条件。
if(!wp.expired) { wp->Use(); // race! }
标签: c++ qt weak-references