接受新对象的宏

时间:2011-09-23 00:13:32

标签: c++ winapi mfc event-handling c-preprocessor

在我的代码中,我有:

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

但我想在EV宏中传递一个创建的对象,例如:

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

这可能吗?因为我无法修改EV宏。

5 个答案:

答案 0 :(得分:5)

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

宏强制每次调用SendEvent都应该创建一个新的动态对象。你的问题不只是使用宏是愚蠢的,例如降低了源代码的可读性。这也是宏不允许您在调用之前创建对象,并且您不能更改宏;在你的话中“我无法修改EV宏”。


因此解决方案很简单:

请勿使用该宏,请直接使用SendEvent,并记住不要delete

答案 1 :(得分:4)

当前编写EV的方式,它将在每次调用时生成一个新对象。但是,该创建不必是与最终传递给SendEvent的类型相同的对象。这是因为预处理器宏和更复杂的表达式的文本性质增加了一些技巧。考虑一下:

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

这将扩展出来,以便你正在运行的新的不是CEvent,而是一个虚拟类......然后你自由,然后整个表达式评估你的事件:

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

(注意:使用?:不如逗号运算符那么好,所以这里有一个浪费的NULL分支从未实际发生。逗号运算符会很好,但预处理器宏特别处理逗号,这是一个无法使用的情况。使其成为线程安全的,留给读者练习。)

为了让它“更干净”,但仍然用EV来表达......没有明确提及SendEvent,你可以制作自己的宏:

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

...或者您可以使用SendEvent,因为它似乎完全符合您的要求。但那里的乐趣在哪里? ;-P


更新

正如@AlfPSteinbach指出的那样,将new变为无操作的更为深奥但轻量级的方法是使用placement new

int dummy;

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

所以现在你正在扩展到:

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

你正在执行一个新的,但这次不需要担心释放结果!因为我不完全确定这是否是犹太洁食。在线程案例中,我提出了自己的问题:

Is it well-defined/legal to placement-new multiple times at the same address?

答案 2 :(得分:2)

完全可行而不改变宏。这只是冒险。请注意,您必须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/

答案 3 :(得分:1)

如果您无法修改EV宏,则无法进行修改。你不能创建自己的SendEvent( event );代替吗?

<强>更新#undef原始宏的可能性,并提供自己的定义吗?假设你只想要新的行为,你可以做

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

但现在您需要使用EV( new event )替换原始类型的通话。

答案 4 :(得分:1)

你可能会泄漏内存,除非SendEvent从内部管理它,比如

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

除此之外,你试过这个吗,它应该可行吗

EV(CEvent)

如果没有,你可以redefine operator new使用CEvent类,这样上面的调用就可以了。

但你的问题真的很不寻常。你确定你在那里走正路吗?