@@ -28,10 +28,11 @@ namespace internal
28
28
// when the slot is disconnected. Bug 167714.
29
29
struct self_and_iter : public notifiable
30
30
{
31
- const std::shared_ptr <signal_impl> self_;
31
+ const std::weak_ptr <signal_impl> self_;
32
32
const signal_impl::iterator_type iter_;
33
33
34
- self_and_iter (const std::shared_ptr<signal_impl>& self, const signal_impl::iterator_type& iter) : self_(self), iter_(iter) {}
34
+ self_and_iter (const std::weak_ptr<signal_impl>& self, const signal_impl::iterator_type& iter)
35
+ : self_(self), iter_(iter) {}
35
36
};
36
37
37
38
signal_impl::signal_impl () : exec_count_(0 ), deferred_(false )
@@ -64,6 +65,9 @@ signal_impl::clear()
64
65
{
65
66
// Don't let signal_impl::notify() erase the slots. It would invalidate the
66
67
// iterator in the following loop.
68
+ // Don't call shared_from_this() here. clear() is called from the destructor.
69
+ // When the destructor is executing, shared_ptr's use_count has reached 0,
70
+ // and it's no longer possible to get a shared_ptr to this.
67
71
const bool saved_deferred = deferred_;
68
72
signal_impl_exec_holder exec (this );
69
73
@@ -179,22 +183,30 @@ void
179
183
signal_impl::notify_self_and_iter_of_invalidated_slot (notifiable* d)
180
184
{
181
185
std::unique_ptr<self_and_iter> si (static_cast <self_and_iter*>(d));
186
+ auto self = si->self_ .lock ();
187
+ if (!self)
188
+ {
189
+ // The signal_impl object is being deleted. The use_count has reached 0.
190
+ // Nothing to do here. exec_count_ > 0 and clear() will restore deferred_.
191
+ return ;
192
+ }
182
193
183
- if (si-> self_ ->exec_count_ == 0 )
194
+ if (self ->exec_count_ == 0 )
184
195
{
185
196
// The deletion of a slot may cause the deletion of a signal_base,
186
197
// a decrementation of si->self_->ref_count_, and the deletion of si->self_.
187
198
// In that case, the deletion of si->self_ is deferred to ~signal_impl_holder().
188
- signal_impl_holder exec (si->self_ );
189
- si->self_ ->slots_ .erase (si->iter_ );
199
+ // https://bugzilla.gnome.org/show_bug.cgi?id=564005#c24
200
+ signal_impl_holder exec (self);
201
+ self->slots_ .erase (si->iter_ );
190
202
}
191
203
else
192
204
{
193
205
// This is occurring during signal emission or slot erasure.
194
206
// => sweep() will be called from ~signal_impl_holder() after signal emission.
195
207
// This is safer because we don't have to care about our
196
208
// iterators in emit(), clear(), and erase().
197
- si-> self_ ->deferred_ = true ;
209
+ self ->deferred_ = true ;
198
210
}
199
211
}
200
212
0 commit comments