What is the difference between queue_free() and call_deferred("queue_free")

Reading the Godot’s source code one can see that the handling of all kinds of stuff substantially changed between Godot 3 and 4. So I’m answering from a Godot 4 perspective. The most relevant pieces of code are in scene/main/scene_tree.cpp.

Godot does processing of deferred function calls as part of its message queue flushing (MessageQueue::get_singleton()->flush()) as far as I can tell. And freeing of queued objects happens when _flush_delete_queue() gets called.

Both of those are performed during physics frames/steps (SceneTree::physics_process) as well as render frames (SceneTree::process). That already tells us that objects queued for deletion during physics processing get freed at the end of a physics time step and don’t stay around until the end of the render frame (unless you call queue_free() during _process() or outside of physics processing, obviously).

The order when the message queue flushing happens vs. the delete queue processing is relevant to answer your question. As the message queue is flushed (and therefore deferred calls processed) before freeing queued objects, calling queue_free() from a deferred call or not doesn’t make a difference in Godot 4, as they will eventually be freed during the same _flush_delete_queue() run.

(Had the order in the C++ code been the other way around, things would be different as calling queue_free() in a deferred fashion would enqueue the object for freeing after the current frame’s _flush_delete_queue() run and would therefore stick around until the end of the next physics or render frame - whichever happened first.)

I haven’t really examined the old Godot 3 code, though, so I can’t say for sure what happened there other than it being structured completely differently. So it may possibly have been different when you used old Godot 3.