2011-02-02 21 views
5

Actualmente estoy trabajando en un juego en C++. dado que no hay un recolector de basura, uno siempre tiene que eliminar cuidadosamente los objetos y también asegurarse de que ya no se acceda a esos objetos una vez que se eliminaron.
Ahora, a medida que crece un proyecto, algunos objetos pueden obtener referencias de más y más lugares. Por ejemplo, mis unidades en el juego pueden ser referenciadas desde el renderizador, desde la jerarquía de escenas, desde el mecanismo de selección, desde el HUD, y así sucesivamente. ahora: si un objeto se elimina, uno debe asegurarse de que todas las demás clases que hacen referencia a este objeto recibirán una notificación al respecto.
O, por decirlo de otra manera: si creo una clase nueva que pueda hacer referencia a una de mis unidades, también tendré que cambiar el código de la unidad (o del administrador de la unidad o cualquier módulo que la elimine) se destruye) para asegurarse de que este nuevo módulo sepa cuándo se elimina la unidad en particular a la que hace referencia actualmente.¿es este un diseño de software aceptable?

Ahora creo que podría haber un enfoque de propósito general impulsado por eventos simples para resolver este problema mediante la creación de una clase base a la que otro objeto puede suscribirse. Algo como esto:

class DeletableBase;//forward declaration 

class ISubscriber{ 
public: 
    virtual someObjectGotDeleted(DeletableBase* deletedObject)=0; 
}; 

class DeletableBase{ 
private: 
    vector<ISubscriber*> subscribers; 
public: 
    virtual ~DeletableBase(){ 
     for(int i=0; i<subscribers.size(); i++) 
      subscribers[i]->someObjectGotDeleted(this); 
    } 
    subscribeForDeleteEvent(ISubscriber* subscriber){ 
     subscribers.push_back(subscriber); 
    } 
}; 

con que - si hacer referencia a cualquier objeto que hereda de esta clase de una nueva clase i simplemente puedo añadir mi mismo como abonado y si el objeto se eliminará de cualquier otro lugar voy a conseguir notificaron al respecto.

¿Es esta una forma "limpia" de codificación?

+2

Pertenece a http://codereview.stackexchange.com/. Sin embargo, tampoco quiero cerrar esto como 'Fuera del tema'. :/ –

+1

Estoy de acuerdo; la pantalla de cierre necesita una opción para migrar a sitios que no sean los pocos que figuran en la lista. (¡Fuera de Meta!) –

+2

Diría que pertenece a programmers.SE, no a la revisión del código. Creo que quien tuvo la brillante idea de tener 4 sitios de programación (en lugar de uno, que era bueno y autónomo) debería avergonzarse. –

Respuesta

6

Si se trata únicamente de gestión de memoria (en lugar de cambio de estado), utilice un puntero inteligente en su lugar. Comience con shared_ptr, luego optimice usando make_shared/allocate_shared o boost::intrusive_ptr si es demasiado lento.

+0

hm - pero si hago lo que significa que voy a tener que comprobar en cada módulo que hace referencia al objeto (a través de un SmartPointer) en cada iteración algo como ' si (myObj-> isStillAlive() == false) reaccionan(); ' – Mat

+0

@Mat: Es que parece siempre (sin tener en cuenta para el diseño de patrones) necesario comprobar la validez del objeto o puntero de alguna manera. Si tiene un puntero al objeto que puede eliminarse (invalidar), debe verificar esto antes de realizar cualquier acción en el objeto. Si tiene un único módulo que controla la duración del objeto, puede usar weak_ptr cuando acceda desde otros módulos. Sin embargo, es necesario comprobar someweakptr.lock() resultado en vez de comprobar isStillAlive() – user396672

+0

@Mat: considerar el uso de una 'boost :: shared_ptr' y varios de impulso :: 'weak_ptr' entonces. –

1

Una cosa que deberás tener en cuenta (especialmente si estás escribiendo un juego) es que cuando uno de tus objetos suscritos se elimina en el hilo principal, tu juego probablemente bloqueará hasta que cada uno de sus suscriptores haya terminado haciendo lo que sea que vaya a hacer al eliminar el objeto. Eso puede afectar el rendimiento del juego si no tienes cuidado.

0

Debe evitar dejar objetos referenciados por otros objetos, pero no al revés. Boost smart pointers hará el 90% del trabajo por usted.

P.S .: Hay un recolector de basura para C++ :-)

+0

¿Qué quieres decir con tu primera frase? Sé que hay recolectores de basura, pero estoy codificando para el iPhone y necesito una tasa de cuadros alta y constante – Mat

+0

¿Por qué no utilizar el Objetivo C, entonces? – Dave

0

en mi humilde opinión, es necesario implementar su propio asignador de memoria. En lugar de observar cada instancia, puede observar memoria liberada para ver el tipo de instancia o clase. Por supuesto, para eso, su asignador de memoria debe ser observable. Puede usar map o set como estructura de datos o multi versiones de ellos para notificar a los observadores de manera más efectiva. Lo que significa que su administrador de memoria será un mediador y también observable.

Además, si estas acciones de liberación o notificación son independientes entre sí, puede usar Command Pattern para separar la ejecución y el contexto del hilo. Espero que esto ayude.

+0

quieres decir algo como esto? 'MyMemoryManager :: subscribe (this, objectToObserve)' – Mat

+0

@Mat Creo que es posible si sobrecarga el operador 'new'. Además, es posible que deba sobrecargar 'borrar'. –

Cuestiones relacionadas