接受新对象的宏

Macro that accept new object

本文关键字:对象 新对象      更新时间:2023-10-16

在我的代码中,我有:

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

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

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

这可能吗?因为我没有办法修改EV

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

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


因此解决方案很简单:

不要使用宏,直接使用SendEvent,记住不要使用delete

当前编写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变成无op的一种更深奥但轻量级的方法是使用新的位置:

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

现在扩展为:

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

你正在执行一个new,但是这次不用担心释放结果!因为我不完全确定这是否合适,特别是在线程的情况下,我提出了自己的问题:

在同一地址多次放置-new是否定义良好/合法?

完全可行,无需更改宏。这太冒险了。注意,您必须设置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/

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

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

把这个放在一边,你试过了吗,应该可以的

EV(CEvent)

如果没有,可以为CEvent类重新定义operator new,这样上面的调用就可以工作了。

但是你的问题真的很不寻常。你确定你走的路对吗?

如果没有办法修改EV宏,那么这是不可能的。你不能创建自己的宏,SendEvent( event );代替?

更新:是否有可能#undef原始宏,并提供您自己的定义?假设您只想要新的行为,您可以使用

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

但是现在你需要用EV( new event )代替原来的调用类型