Macro that accept new object

99封情书 提交于 2019-12-11 12:57:27

问题


In my code, I have:

#define EV( event ) SendEvent( new event );
EV( 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.


回答1:


#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.




回答2:


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?




回答3:


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/




回答4:


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 ?




回答5:


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 ).



来源:https://stackoverflow.com/questions/7522949/macro-that-accept-new-object

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!