Macro that accept new object
In my code, I have:
#define EV( event ) SendEvent( new event );
E开发者_C百科V( evFormat );
But I want to pass a created object in the EV
macro, like:
CEvent *ev = new CEvent();
EV( ev );
Is this possible? Because there is no way I will modify the EV
macro.
#define EV( event ) SendEvent( new event ); // Can't be changed.
The macro enforces that each call to SendEvent
should create a new dynamic object. Your problem is not just that using a macro for that is stupid and e.g. reduces the readability of your source code. It is also that the macro does not allow you to create the object earlier than the call, and that you can't change the macro; in your words "there is no way I will modify the EV
macro".
The solution is therefore simple:
Don't use the macro, use SendEvent
directly, and remember to not delete
.
The way EV
is currently written, it will generate a new object on each call. But that creation doesn't have to be of an object of the same type as what is ultimately passed to SendEvent. That's because the textual nature of preprocessor macros and more complex expressions adds some tricks. Consider this:
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 );
That will expand out so that the new you're running is not of a CEvent, but of a dummy class...which you then free, and then the whole expression evaluates to your event:
SendEvent( new dummy && dummy::dofree() ? ev : NULL );
(Note: Using ?: is not as nice as the comma operator, so there's a wasted NULL branch here that never actually happens. The comma operator would be nice, but preprocessor macros treat commas specially and this is one of the cases where it can't be used. Making it thread-safe is left as an exercise for the reader.)
To make it "cleaner" but still express it in terms of EV
...without explicitly mentioning SendEvent
at all, you could make your own macro:
#define EV2(event) EV( dummy && dummy::dofree() ? event : NULL )
...or you could just use SendEvent since it seems to do exactly what you want. But where's the fun in that? ;-P
UPDATE:
As @AlfPSteinbach points out, a more esoteric but lightweight way of turning your new
into a no-op is with placement new:
int dummy;
CEvent *ev = new CEvent(this);
EV( (&dummy) int ? ev : NULL );
So now you're expanding into:
SendEvent( new (&dummy) int ? ev : NULL );
You're executing a new, but this time without needing to worry about freeing the result! Because I wasn't entirely sure if this was kosher esp. in threading cases, I made its own question:
Is it well-defined/legal to placement-new multiple times at the same address?
Totally doable without altering the macro. It's just risky. Note that you'll have to 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/
You might be leaking memory, unless SendEvent manages it from inside, something like
void SendEvent(const Event *ev) {
doSendEvent(ev);
delete ev;
}
That aside, have you tried this, it should work
EV(CEvent)
If not, you could redefine operator new for the class CEvent so the above call would work.
But your question is really unusual. Are you sure you there you are going down the right path ?
If there is no way you will modify the EV
macro, then it isn't possible. Can't you create your own macro that does SendEvent( event );
instead?
Update:
Would it be a possibility to #undef
the original macro, and provide your own definition of it? Assuming you only want the new behavior, you could do
#undef EV
#define EV( event ) SendEvent( event );
but now you will need to replace the original kind of call with EV( new event )
.
精彩评论