How to check is pointer pointing to object that was queued_free (GDNative c++)?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Robotex

I often have a situation when bot shoot to another bot and then died when bullet is flied still. But then, after bot was removed from scene by queue_free, bullet can hit some bot and try to access pointer that points to died bot (each bullet has pointer to shooter).

So, is it possible to check that pointer is not valid anymore?

There is a function in GDScript called, is_queued_for_deletion().
Check if there is a GDNative equivalent function.

nightrobin | 2021-02-12 15:39

No, this function will not work in this case, because object can be deleted a long time ago but something still has pointer to it that is not valid. So, calling is_queued_for_deleting will cause the crash.

I solved this problem, I’ll add answer

Robotex | 2021-02-12 15:46

:bust_in_silhouette: Reply From: Robotex

I solved this problem by replacing all pointers by instance_id.

Then, I added a manager that returns pointer by instance_id if object is still alive or nullptr if not.

Now, everything works excellent

// SceneObjectsManager.h
#pragma once

#include "Core/Types.h"
#include "GameAgent.h"

#include <Dictionary.hpp>
#include <Node.hpp>

class SceneObjectsManager
{
public:
	SceneObjectsManager();

	template <class T>
	void registerObject(T* gameAgent);

	void destroyObject(int instance_id);

	bool isInstanceExists(int instance_id);

	void registerAgent(godot::GameAgent* gameAgent);
	void registerNode(godot::Node* node);

	godot::GameAgent* getAgentByInstanceId(int instance_id);
	godot::Node* getNodeByInstanceId(int instance_id);

public:
	static constexpr s64 NULL_REFERENCE = -1;

protected:
	godot::Dictionary sceneObjects;
};

template<class T>
inline void SceneObjectsManager::registerObject(T* object)
{
	if (object) {
		sceneObjects[object->get_instance_id()] = object;
	}
}

// SceneObjectsManager.cpp
#include "SceneObjectsManager.h"

SceneObjectsManager::SceneObjectsManager()
{
	sceneObjects.clear();
}

void SceneObjectsManager::registerAgent(godot::GameAgent* gameAgent)
{
	registerObject<godot::GameAgent>(gameAgent);
}

void SceneObjectsManager::registerNode(godot::Node* node)
{
	registerObject<godot::Node>(node);
}

void SceneObjectsManager::destroyObject(int instance_id)
{
	if (sceneObjects.has(instance_id)) {
		sceneObjects[instance_id].call("queue_free", nullptr, 0);
		sceneObjects.erase(instance_id);
	}
}

godot::GameAgent* SceneObjectsManager::getAgentByInstanceId(int instance_id)
{
	if (!sceneObjects.has(instance_id)) {
		return nullptr;
	} else {
		return sceneObjects[instance_id];
	}
}

godot::Node* SceneObjectsManager::getNodeByInstanceId(int instance_id)
{
	if (!sceneObjects.has(instance_id)) {
		return nullptr;
	}
	else {
		return sceneObjects[instance_id];
	}
}

bool SceneObjectsManager::isInstanceExists(int instance_id)
{
	return sceneObjects.has(instance_id);
}