@@ -254,11 +254,45 @@ Object::Connection::Connection(const Variant &p_variant) {
254254bool Object::_predelete () {
255255 _predelete_ok = 1 ;
256256 notification (NOTIFICATION_PREDELETE, true );
257- if (_predelete_ok) {
258- _class_name_ptr = nullptr ; // Must restore, so constructors/destructors have proper class name access at each stage.
259- notification (NOTIFICATION_PREDELETE_CLEANUP, true );
257+ if (!_predelete_ok) {
258+ return false ;
259+ }
260+
261+ _class_name_ptr = nullptr ; // Must restore, so constructors/destructors have proper class name access at each stage.
262+ notification (NOTIFICATION_PREDELETE_CLEANUP, true );
263+
264+ // Destruction order starts with the most derived class, and progresses towards the base Object class:
265+ // Script subclasses -> GDExtension subclasses -> C++ subclasses -> Object
266+ if (script_instance) {
267+ memdelete (script_instance);
260268 }
261- return _predelete_ok;
269+ script_instance = nullptr ;
270+
271+ if (_extension) {
272+ #ifdef TOOLS_ENABLED
273+ if (_extension->untrack_instance ) {
274+ _extension->untrack_instance (_extension->tracking_userdata , this );
275+ }
276+ #endif
277+ if (_extension->free_instance ) {
278+ _extension->free_instance (_extension->class_userdata , _extension_instance);
279+ }
280+ _extension = nullptr ;
281+ _extension_instance = nullptr ;
282+ }
283+ #ifdef TOOLS_ENABLED
284+ else if (_instance_bindings != nullptr ) {
285+ Engine *engine = Engine::get_singleton ();
286+ GDExtensionManager *gdextension_manager = GDExtensionManager::get_singleton ();
287+ if (engine && gdextension_manager && engine->is_extension_reloading_enabled ()) {
288+ for (uint32_t i = 0 ; i < _instance_binding_count; i++) {
289+ gdextension_manager->untrack_instance_binding (_instance_bindings[i].token , this );
290+ }
291+ }
292+ }
293+ #endif
294+
295+ return true ;
262296}
263297
264298void Object::cancel_free () {
@@ -2273,35 +2307,6 @@ void Object::assign_class_name_static(const Span<char> &p_name, StringName &r_ta
22732307}
22742308
22752309Object::~Object () {
2276- if (script_instance) {
2277- memdelete (script_instance);
2278- }
2279- script_instance = nullptr ;
2280-
2281- if (_extension) {
2282- #ifdef TOOLS_ENABLED
2283- if (_extension->untrack_instance ) {
2284- _extension->untrack_instance (_extension->tracking_userdata , this );
2285- }
2286- #endif
2287- if (_extension->free_instance ) {
2288- _extension->free_instance (_extension->class_userdata , _extension_instance);
2289- }
2290- _extension = nullptr ;
2291- _extension_instance = nullptr ;
2292- }
2293- #ifdef TOOLS_ENABLED
2294- else if (_instance_bindings != nullptr ) {
2295- Engine *engine = Engine::get_singleton ();
2296- GDExtensionManager *gdextension_manager = GDExtensionManager::get_singleton ();
2297- if (engine && gdextension_manager && engine->is_extension_reloading_enabled ()) {
2298- for (uint32_t i = 0 ; i < _instance_binding_count; i++) {
2299- gdextension_manager->untrack_instance_binding (_instance_bindings[i].token , this );
2300- }
2301- }
2302- }
2303- #endif
2304-
23052310 if (_emitting) {
23062311 // @todo this may need to actually reach the debugger prioritarily somehow because it may crash before
23072312 ERR_PRINT (vformat (" Object '%s' was freed or unreferenced while a signal is being emitted from it. Try connecting to the signal using 'CONNECT_DEFERRED' flag, or use queue_free() to free the object (if this object is a Node) to avoid this error and potential crashes." , to_string ()));
0 commit comments