@@ -238,9 +238,16 @@ PYAObjectBase::object_destroyed ()
238
238
239
239
detach ();
240
240
241
- // NOTE: this may delete "this"!
242
- if (!prev_owner) {
243
- Py_DECREF (py_object ());
241
+ if (! prev_owner) {
242
+ const gsi::ClassBase *cls = cls_decl ();
243
+ if (cls && cls->is_managed ()) {
244
+ // If the object was owned on C++ side before, we need to decrement the
245
+ // reference count to reflect the fact, that there no longer is an external
246
+ // owner.
247
+ // NOTE: this may delete "this", hence we return
248
+ Py_DECREF (py_object ());
249
+ return ;
250
+ }
244
251
}
245
252
246
253
}
@@ -249,31 +256,44 @@ PYAObjectBase::object_destroyed ()
249
256
void
250
257
PYAObjectBase::release ()
251
258
{
259
+ // "release" means to release ownership of the C++ object on the C++ side.
260
+ // In other words: to transfer ownership to the script side. Specifically to
261
+ // transfer it to the Python domain.
262
+
252
263
// If the object is managed we first reset the ownership of all other clients
253
264
// and then make us the owner
254
265
const gsi::ClassBase *cls = cls_decl ();
255
266
if (cls && cls->is_managed ()) {
256
267
void *o = obj ();
257
268
if (o) {
269
+ // NOTE: "keep" means "move ownership of the C++ object to C++". In other words,
270
+ // release ownership of the C++ object on script side.
258
271
cls->gsi_object (o)->keep ();
272
+ if (! m_owned) {
273
+ // We have to *decrement* the reference count as now there is no other entity
274
+ // holding a reference to this Python object.
275
+ // NOTE: this may delete "this", hence we return
276
+ m_owned = true ;
277
+ Py_DECREF (py_object ());
278
+ return ;
279
+ }
259
280
}
260
281
}
261
282
262
- // NOTE: this is fairly dangerous
263
- if (!m_owned) {
264
- m_owned = true ;
265
- // NOTE: this may delete "this"! TODO: this should not happen. Can we assert that somehow?
266
- Py_DECREF (py_object ());
267
- }
283
+ m_owned = true ;
268
284
}
269
285
270
286
void
271
287
PYAObjectBase::keep_internal ()
272
288
{
273
289
if (m_owned) {
290
+ // "keep" means to transfer ownership of the C++ object to C++ side, while
291
+ // "m_owned" refers to ownership on the Python side. So if we perform this
292
+ // transfer, we need to reflect the fact that there is another entity holding
293
+ // a reference.
274
294
Py_INCREF (py_object ());
275
- m_owned = false ;
276
295
}
296
+ m_owned = false ;
277
297
}
278
298
279
299
void
@@ -284,9 +304,11 @@ PYAObjectBase::keep ()
284
304
void *o = obj ();
285
305
if (o) {
286
306
if (cls->is_managed ()) {
307
+ // dispatch the keep notification - this will call "keep_internal" through the
308
+ // event handler (StatusChangedListener)
287
309
cls->gsi_object (o)->keep ();
288
310
} else {
289
- keep_internal () ;
311
+ m_owned = false ;
290
312
}
291
313
}
292
314
}
@@ -341,16 +363,18 @@ PYAObjectBase::set (void *obj, bool owned, bool const_ref, bool can_destroy)
341
363
342
364
if (cls->is_managed ()) {
343
365
gsi::ObjectBase *gsi_object = cls->gsi_object (m_obj);
344
- // Consider the case of "keep inside constructor"
345
366
if (gsi_object->already_kept ()) {
346
- keep_internal ();
367
+ // Consider the case of "keep inside constructor"
368
+ m_owned = false ;
369
+ }
370
+ if (! m_owned) {
371
+ // "m_owned = false" means ownership of the C++ object is on C++ side,
372
+ // and not on script side. In that case, we need to increment the
373
+ // reference count to reflect the fact that there is an external owner.
374
+ Py_INCREF (py_object ());
347
375
}
348
376
gsi_object->status_changed_event ().add (mp_listener, &StatusChangedListener::object_status_changed);
349
377
}
350
-
351
- if (!m_owned) {
352
- Py_INCREF (py_object ());
353
- }
354
378
}
355
379
356
380
// TODO: a static (singleton) instance is not thread-safe
@@ -587,7 +611,7 @@ PYAObjectBase::obj ()
587
611
throw tl::Exception (tl::to_string (tr (" Object has been destroyed already" )));
588
612
} else {
589
613
// delayed creation of a detached C++ object ..
590
- set (cls_decl ()->create (), true , false , true );
614
+ set (cls_decl ()->create (), true , false , true );
591
615
}
592
616
}
593
617
0 commit comments