c++ Macro que acepta nuevo objeto



winapi mfc (4)

#define EV( event ) SendEvent( new event );    // Can't be changed.

La macro impone que cada llamada a SendEvent debería crear un nuevo objeto dinámico. Su problema no es solo que usar una macro para eso es estúpido y, por ejemplo, reduce la legibilidad de su código fuente. También es que la macro no le permite crear el objeto antes que la llamada, y que no puede cambiar la macro; en sus palabras "no hay manera de que modifique la macro EV ".

La solución es simple:

No use la macro, use SendEvent directamente y recuerde no delete .

En mi código, tengo:

#define EV( event ) SendEvent( new event );
EV( evFormat );

Pero quiero pasar un objeto creado en la macro EV , como:

CEvent *ev = new CEvent();
EV( ev );

es posible? Porque no hay forma de que modifique la macro EV .


Answer #1

La forma en que EV se escribe actualmente generará un nuevo objeto en cada llamada. Pero esa creación no tiene que ser de un objeto del mismo tipo que lo que finalmente se pasa a SendEvent. Esto se debe a que la naturaleza textual de las macros de preprocesador y las expresiones más complejas agrega algunos trucos. Considera esto:

class dummy {
private:
    static dummy* freeme;
public:
    dummy() { freeme = this; }
    static bool dofree() { delete freeme; return true; }
};
dummy* dummy::freeme;

CEvent *ev = new CEvent(this);
EV( dummy && dummy::dofree() ? ev : NULL );

Eso se ampliará para que lo nuevo que estás ejecutando no sea de un CEvent, sino de una clase ficticia ... que luego liberas, y luego toda la expresión evalúa tu evento:

SendEvent( new dummy && dummy::dofree() ? ev : NULL );

(Nota: el uso de?: No es tan bueno como el operador de coma, por lo que hay una rama NULL desperdiciada aquí que nunca sucede realmente. El operador de coma sería bueno, pero las macros de preprocesador tratan las comas especialmente y este es uno de los casos donde puede No se puede usar. Dejarlo a prueba de hilos se deja como un ejercicio para el lector.

Para que sea más "limpio" pero aún así lo exprese en términos de EV ... sin mencionar explícitamente a SendEvent , puede crear su propia macro:

#define EV2(event) EV( dummy && dummy::dofree() ? event : NULL )

... o podría usar SendEvent ya que parece hacer exactamente lo que quiere. Pero, ¿dónde está la diversión en eso? ;-PAG

ACTUALIZAR:

Como señala @AlfPSteinbach, una forma más esotérica pero ligera de convertir lo new en no-operativo es con la colocación nueva :

int dummy;

CEvent *ev = new CEvent(this);
EV( (&dummy) int ? ev : NULL );

Entonces ahora estás expandiéndote a:

SendEvent( new (&dummy) int ? ev : NULL );

Estás ejecutando una nueva, ¡pero esta vez sin necesidad de preocuparte por liberar el resultado! Porque no estaba del todo seguro de si esto era especialmente kosher. al entablar casos, hice su propia pregunta:

¿Está bien definido / legal para la colocación, nuevo varias veces en la misma dirección?


Answer #2

Puede que esté perdiendo memoria, a menos que SendEvent lo administre desde adentro, algo así como

void SendEvent(const Event *ev) {
     doSendEvent(ev);
     delete ev;
}

Aparte de eso, si has probado esto, debería funcionar

EV(CEvent)

De lo contrario, podría redefinir el operador nuevo para la clase CEvent para que funcione la llamada anterior.

Pero tu pregunta es realmente inusual. ¿Estás seguro de que estás por el camino correcto?


Answer #3

Totalmente factible sin alterar la macro. Es arriesgado. Tenga en cuenta que deberá delete []

#include <memory>

struct CEvent {};
void SendEvent(CEvent*) {}

#define EV( event ) SendEvent( new event );

int main() {
    char *cev = new char[sizeof(CEvent)];
    CEvent* ev = (CEvent*)cev;

    EV( (ev)CEvent );

    ev->~CEvent();
    delete [] cev;
}

http://ideone.com/





c-preprocessor